#include "sonic.h"
#include "joypad.h"
#include "sprite.h"
#include "mapping.h"
#include "collision.h"
#include "misc.h"  //CalcSine...
#include <stdio.h>
#include <math.h>

#define player objects[0]
#define SWAPLONG(val) (((val&0xFFFF0000) >> 16) + ((val&0x0000FFFF) << 16))   

extern object *objects;


void (*Sonic_Index[5])();
void (*Sonic_Modes[4])();

byte v_sgfx_buffer[0x300];
extern byte Art_Sonic[];

extern byte v_jpadhold1;
extern byte v_jpadpress1;
extern byte v_jpadhold2;
extern byte v_jpadpress2;

word v_debuguse;

extern word v_zone;      //current zone number
word v_air;

extern word v_limitleft2;
extern word v_limitright2;
extern word v_limitbtm2;

extern word v_lookshift;

signed short v_anglebuffer;
signed short FFFFF76A;

bool f_lockscreen;

extern byte v_256loop1;
extern byte v_256loop2;
extern byte v_256roll1;
extern byte v_256roll2;

bool v_shield;     //   shield status (00 = no; 01 = yes)
bool v_invinc;     //	= $FFFFFE2D	; invinciblity status (00 = no; 01 = yes)
bool v_shoes;      //	= $FFFFFE2E	; speed shoes status (00 = no; 01 = yes)
extern bool v_lastlamp;   //	= $FFFFFE30	; number of the last lamppost you hit
bool f_wtunnelmode;
extern bool f_lockmulti;
bool f_wtunnelallow;
bool f_jumponly;
//extern bool v_obj6B
extern bool f_lockctrl;

extern word v_itembonus;  //hud.c

word v_sonspeedmax;
word v_sonspeedacc;
word v_sonspeeddec;
byte v_sonframenum;
bool f_sonframechg;

byte FFFFFFEC;
byte FFFFFFED;
byte FFFFFFEE;
byte FFFFFFEF;

byte SonAni_Walk[8]={ 0xFF, fr_Walk13, fr_Walk14, fr_Walk15, fr_Walk16, fr_Walk11, fr_Walk12, afEnd };
byte SonAni_Run[8]={ 0xFF, fr_Run11, fr_Run12, fr_Run13, fr_Run14, afEnd, afEnd, afEnd };
byte SonAni_Roll[8]= { 0xFE, fr_Roll1, fr_Roll2, fr_Roll3, fr_Roll4, fr_Roll5, afEnd, afEnd }; 
byte SonAni_Roll2[8]= { 0xFE, fr_Roll1, fr_Roll2, fr_Roll5, fr_Roll3, fr_Roll4, afEnd, afEnd };
byte SonAni_Push[8]= { 0xFD, fr_Push1, fr_Push2, fr_Push3, fr_Push4, afEnd, afEnd, afEnd };
byte SonAni_Wait[21]= { 0x17, fr_Stand, fr_Stand, fr_Stand, fr_Stand, fr_Stand, fr_Stand, fr_Stand, fr_Stand, fr_Stand,
                         fr_Stand, fr_Stand, fr_Stand, fr_Wait2, fr_Wait1, fr_Wait1, fr_Wait1, fr_Wait2, fr_Wait3, afBack, 2};
                         
byte SonAni_Balance[4]={0x1F, fr_Balance1, fr_Balance2, afEnd };
byte SonAni_LookUp[3]={0x3F, fr_Lookup, afEnd };
 
byte SonAni_Duck[3]={0x3F, fr_Duck, afEnd };
byte SonAni_Warp1[3]={0x3F, fr_Warp1, afEnd };
byte SonAni_Warp2[3]={0x3F, fr_Warp2, afEnd };
byte SonAni_Warp3[3]={0x3F, fr_Warp3, afEnd };
byte SonAni_Warp4[3]={0x3F, fr_Warp4, afEnd };
byte SonAni_Stop[4]={ 7,	fr_Stop1, fr_Stop2, afEnd };
byte SonAni_Float1[4]={ 7,	fr_Float1, fr_Float4, afEnd };
byte SonAni_Float2[7]={ 7,	fr_Float1, fr_Float2, fr_Float5, fr_Float3, fr_Float6, afEnd};
byte SonAni_Spring[4]={0x2F, fr_Spring, afChange, id_Walk };

byte SonAni_Hang[4]={ 4, fr_Hang1, fr_Hang2, afEnd };
byte SonAni_Leap1[6]= {0xF, fr_Leap1, fr_Leap1, fr_Leap1, afBack, 1};
byte SonAni_Leap2[5]= {0xF, fr_Leap1, fr_Leap2, afBack, 1};
byte SonAni_Surf[3]= {0x3F, fr_Surf, afEnd };
byte SonAni_GetAir[7]=	{0xB, fr_GetAir, fr_GetAir, fr_Walk15, fr_Walk16, afChange, id_Walk };

byte SonAni_Burnt[3]= {0x20, fr_Burnt, afEnd};
byte SonAni_Drown[3]= {0x2F, fr_Drown, afEnd};
byte SonAni_Death[3]= { 3,	fr_Death, afEnd};
byte SonAni_Shrink[9]= {3,	fr_Shrink1, fr_Shrink2, fr_Shrink3, fr_Shrink4, fr_Shrink5, fr_Null, afBack, 1 };
byte SonAni_Hurt[3]= { 3,	fr_Injury, afEnd };

byte SonAni_WaterSlide[4]={ 7, fr_Injury, fr_WaterSlide, afEnd };
byte SonAni_Null[4]={0x77, fr_Null, afChange, id_Walk };
byte SonAni_Float3[7]=	{ 3, fr_Float1, fr_Float2, fr_Float5, fr_Float3, fr_Float6, afEnd };
byte SonAni_Float4[4]=	{ 3, fr_Float1, afChange, id_Walk };

byte *Ani_Sonic[32]={ SonAni_Walk, SonAni_Run, SonAni_Roll, SonAni_Roll2, SonAni_Push, SonAni_Wait, SonAni_Balance, SonAni_LookUp, SonAni_Duck, SonAni_Warp1,
                      SonAni_Warp2, SonAni_Warp3, SonAni_Warp4, SonAni_Stop, SonAni_Float1, SonAni_Float2, SonAni_Spring, SonAni_Hang, SonAni_Leap1, SonAni_Leap2,
                      SonAni_Surf, SonAni_GetAir, SonAni_Burnt, SonAni_Drown, SonAni_Drown, SonAni_Death, SonAni_Shrink, SonAni_Hurt, SonAni_WaterSlide, SonAni_Null,
                      SonAni_Float3, SonAni_Float4 };

byte SonPLC_Null[1] = { 0 };
byte SonPLC_Stand[9] = { 4, 0x20, 0, 0x70, 3, 0x20, 0xB, 0x20, 0xE };
byte SonPLC_Wait1[7] = { 3, 0x50, 0x11, 0x50, 0x17, 0x20, 0x1D };
byte SonPLC_Wait2[7] = { 3, 0x50, 0x20, 0x50, 0x17, 0x20, 0x1D };
byte SonPLC_Wait3[7] = { 3, 0x50, 0x20, 0x50, 0x17, 0x20, 0x26 };
byte SonPLC_LookUp[7] = { 3, 0x80, 0x29, 0x20, 0xB, 0x20, 0xE };
byte SonPLC_Walk11[9] = { 4, 0x70, 0x32, 0x50, 0x3A, 0x50, 0x40, 0x10, 0x46 };
byte SonPLC_Walk12[5] = { 2, 0x70, 0x32, 0xB0, 0x48 };
byte SonPLC_Walk13[5] = { 2, 0x50, 0x54, 0x80, 0x5A };
byte SonPLC_Walk14[9] = { 4, 0x50, 0x54, 0x50, 0x63, 0x50, 0x69, 0x10, 0x6F };
byte SonPLC_Walk15[5] = { 2, 0x50, 0x54, 0xB0, 0x71 };
byte SonPLC_Walk16[7] = { 3, 0x70, 0x32, 0x30, 0x7D, 0x50, 0x81 };
byte SonPLC_Walk21[11] = { 5, 0x50, 0x87, 0x50, 0x8D, 0x20, 0x93, 0x50, 0x96, 0, 0x9C };
byte SonPLC_Walk22[13] = { 6, 0x50, 0x87, 0x10, 0x9D, 0x30, 0x9F, 0x50, 0xA3, 0x30, 0xA9, 0, 0xAD };
byte SonPLC_Walk23[9] = { 4, 0x50, 0xAE, 0x10, 0xB4, 0x70, 0xB6, 0x20, 0xBE };
byte SonPLC_Walk24[11] = { 5, 0x50, 0xC1, 0x30, 0xC7, 0x70, 0xCB, 0x20, 0xD3, 0x10, 0xD6 };
byte SonPLC_Walk25[9] = { 4, 0x50, 0xC1, 0x10, 0xD8, 0x70, 0xDA, 0x20, 0xE2 };
byte SonPLC_Walk26[11] = { 5, 0x50, 0x87, 0x10, 0x9D, 0, 0x93, 0x70, 0xE5, 0x20, 0xED };
byte SonPLC_Walk31[9] = { 4, 0x70, 0xF0, 0x50, 0xF8, 0x10, 0xFE, 0x51, 0 };
byte SonPLC_Walk32[5] = { 2, 0x70, 0xF0, 0xB1, 6 };
byte SonPLC_Walk33[5] = { 2, 0x51, 0x12, 0x81, 0x18 };
byte SonPLC_Walk34[9] = { 4, 0x51, 0x12, 0x51, 0x21, 0x11, 0x27, 0x51, 0x29 };
byte SonPLC_Walk35[5] = { 2, 0x51, 0x12, 0xB1, 0x2F };
byte SonPLC_Walk36[7] = { 3, 0x70, 0xF0, 1, 6, 0x81, 0x3B };
byte SonPLC_Walk41[13] = { 6, 0x51, 0x44, 0x11, 0x4A, 0x11, 0x4C, 0x81, 0x4E, 1, 0x57, 1, 0x58 };
byte SonPLC_Walk42[13] = { 6, 0x51, 0x44, 0x21, 0x59, 0x11, 0x5C, 0x11, 0x5E, 0x81, 0x60, 1, 0x57 };
byte SonPLC_Walk43[9] = { 4, 0x51, 0x69, 0x11, 0x6F, 0x81, 0x71, 0x11, 0x7A };
byte SonPLC_Walk44[11] = { 5, 0x51, 0x7C, 0x21, 0x82, 0x11, 0x85, 0x71, 0x87, 0x21, 0x8F };
byte SonPLC_Walk45[9] = { 4, 0x51, 0x7C, 0x11, 0x92, 0x81, 0x94, 0x11, 0x9D };
byte SonPLC_Walk46[11] = { 5, 0x51, 0x44, 0x81, 0x9F, 0x11, 0x5E, 0x11, 0xA8, 1, 0x57 };
byte SonPLC_Run11[5] = { 2, 0x51, 0xAA, 0xB1, 0xB0 };
byte SonPLC_Run12[5] = { 2, 0x50, 0x54, 0xB1, 0xBC };
byte SonPLC_Run13[5] = { 2, 0x51, 0xAA, 0xB1, 0xC8 };
byte SonPLC_Run14[5] = { 2, 0x50, 0x54, 0xB1, 0xD4 };
byte SonPLC_Run21[9] = { 4, 0x51, 0xE0, 0x11, 0xE6, 0xB1, 0xE8, 1, 0xF4 };
byte SonPLC_Run22[7] = { 3, 0x51, 0xF5, 0x11, 0xFB, 0xB1, 0xFD };
byte SonPLC_Run23[9] = { 4, 0x51, 0xE0, 0x12, 9, 0xB2, 0xB, 1, 0xF4 };
byte SonPLC_Run24[7] = { 3, 0x51, 0xF5, 0x11, 0xFB, 0xB2, 0x17 };
byte SonPLC_Run31[5] = { 2, 0x52, 0x23, 0xB2, 0x29 };
byte SonPLC_Run32[5] = { 2, 0x51, 0x12, 0xB2, 0x35 };
byte SonPLC_Run33[5] = { 2, 0x52, 0x23, 0xB2, 0x41 };
byte SonPLC_Run34[5] = { 2, 0x51, 0x12, 0xB2, 0x4D };
byte SonPLC_Run41[9] = { 4, 0x52, 0x59, 0x12, 0x5F, 0xB2, 0x61, 2, 0x6D };
byte SonPLC_Run42[5] = { 2, 0x72, 0x6E, 0xB2, 0x76 };
byte SonPLC_Run43[9] = { 4, 0x52, 0x59, 0x12, 0x82, 0xB2, 0x84, 2, 0x6D };
byte SonPLC_Run44[5] = { 2, 0x72, 0x6E, 0xB2, 0x90 };
byte SonPLC_Roll1[3] = { 1, 0xF2, 0x9C };
byte SonPLC_Roll2[3] = { 1, 0xF2, 0xAC };
byte SonPLC_Roll3[3] = { 1, 0xF2, 0xBC };
byte SonPLC_Roll4[3] = { 1, 0xF2, 0xCC };
byte SonPLC_Roll5[3] = { 1, 0xF2, 0xDC };
byte SonPLC_Warp1[5] = { 2, 0xB2, 0xEC, 0x22, 0xF8 };
byte SonPLC_Warp2[3] = { 1, 0xF2, 0xFB };
byte SonPLC_Warp3[5] = { 2, 0xB3, 0xB, 0x23, 0x17 };
byte SonPLC_Warp4[3] = { 1, 0xF3, 0x1A };
byte SonPLC_Stop1[5] = { 2, 0x53, 0x2A, 0xB3, 0x30 };
byte SonPLC_Stop2[9] = { 4, 0x53, 0x3C, 0x73, 0x42, 0x13, 0x4A, 3, 0x4C }; 
byte SonPLC_Duck[9] = { 4, 0x13, 0x4D, 0x73, 0x4F, 0x23, 0x57, 3, 0x5A };
byte SonPLC_Balance1[7] = { 3, 0x23, 0x5B, 0x23, 0x5E, 0xF3, 0x61 };
byte SonPLC_Balance2[7] = { 3, 0xB3, 0x71, 0x73, 0x7D, 0, 0x71 };
byte SonPLC_Float1[7] = { 3, 0x73, 0x85, 0x33, 0x8D, 0x23, 0x91 };
byte SonPLC_Float2[3] = { 1, 0x83, 0x94 };
byte SonPLC_Float3[7] = { 3, 0x73, 0x9D, 3, 0xA5, 0x33, 0xA6 };
byte SonPLC_Float4[7] = { 3, 0x73, 0xAA, 0x33, 0xB2, 0x23, 0xB6 };
byte SonPLC_Spring[7] = { 3, 0xB3, 0xB9, 0x13, 0xC5, 3, 0xC7 };
byte SonPLC_Hang1[9] = { 4, 0xB3, 0xC8, 0x33, 0xD4, 3, 0xD8, 3, 0xD9 };
byte SonPLC_Hang2[9] = { 4, 0xB3, 0xDA, 0x33, 0xE6, 3, 0xEA, 3, 0xEB };
byte SonPLC_Leap1[11] = { 5, 0x83, 0xEC, 0x13, 0xF5, 0x53, 0xF7, 0x13, 0xFD, 3, 0xFF };
byte SonPLC_Leap2[11] = { 5, 0x84, 0, 0x14, 9, 0x53, 0xF7, 0x13, 0xFD, 3, 0xFF };
byte SonPLC_Push1[5] = { 2, 0x84, 0xB, 0x74, 0x14 };
byte SonPLC_Push2[7] = { 3, 0x84, 0x1C, 0x24, 0x25, 0x14, 0x28 };
byte SonPLC_Push3[5] = { 2, 0x84, 0x2A, 0x74, 0x33 };
byte SonPLC_Push4[7] = { 3, 0x84, 0x1C, 0x24, 0x3B, 0x14, 0x3E };
byte SonPLC_Surf[5] = { 2, 0x54, 0x40, 0xB4, 0x46 };
byte SonPLC_BubStand[7] = { 3, 0x84, 0x52, 0x34, 0x5B, 4, 0x5F };
byte SonPLC_Death[7] = { 3, 0x74, 0x60, 0x14, 0x68, 0xB4, 0x6A };
byte SonPLC_Drown[11] = { 5, 0x74, 0x76, 0x14, 0x7E, 0x54, 0x80, 0x34, 0x86, 4, 0x8A };
byte SonPLC_Burnt[11] = { 5, 0x74, 0x8B, 0x14, 0x7E, 0x54, 0x93, 0x34, 0x86, 4, 0x8A };
byte SonPLC_Shrink1[5] = { 2, 0x24, 0x99, 0xF4, 0x9C };
byte SonPLC_Shrink2[7] = { 3, 0x24, 0xAC, 0xB4, 0xAF, 0x24, 0xBB };
byte SonPLC_Shrink3[3] = { 1, 0xB4, 0xBE };
byte SonPLC_Shrink4[3] = { 1, 0x54, 0xCA };
byte SonPLC_Shrink5[3] = { 1, 0x14, 0xD0 };
byte SonPLC_Injury[7] = { 3, 0xB4, 0xD2, 0x14, 0xDE, 0x34, 0xE0 };
byte SonPLC_GetAir[7] = { 3, 0x54, 0xE4, 0xB4, 0xEA, 0x10, 0x6D };
byte SonPLC_WaterSlide[5] = { 2, 0xF4, 0xF6, 0x25, 6 };

byte *SonicDynPLC[88]={ SonPLC_Null,   SonPLC_Stand,  SonPLC_Wait1,  SonPLC_Wait2,  SonPLC_Wait3,  SonPLC_LookUp, SonPLC_Walk11, SonPLC_Walk12, SonPLC_Walk13, SonPLC_Walk14,
			SonPLC_Walk15, SonPLC_Walk16, SonPLC_Walk21, SonPLC_Walk22, SonPLC_Walk23, SonPLC_Walk24, SonPLC_Walk25, SonPLC_Walk26, SonPLC_Walk31, SonPLC_Walk32,
			SonPLC_Walk33, SonPLC_Walk34, SonPLC_Walk35, SonPLC_Walk36, SonPLC_Walk41, SonPLC_Walk42, SonPLC_Walk43, SonPLC_Walk44, SonPLC_Walk45, SonPLC_Walk46,
			SonPLC_Run11,  SonPLC_Run12,  SonPLC_Run13,  SonPLC_Run14,  SonPLC_Run21,  SonPLC_Run22,  SonPLC_Run23,  SonPLC_Run24,  SonPLC_Run31,  SonPLC_Run32,
		        SonPLC_Run33,  SonPLC_Run34,  SonPLC_Run41,  SonPLC_Run42,  SonPLC_Run43,  SonPLC_Run44,  SonPLC_Roll1,  SonPLC_Roll2,  SonPLC_Roll3,  SonPLC_Roll4,
                        SonPLC_Roll5,  SonPLC_Warp1,  SonPLC_Warp2,  SonPLC_Warp3,  SonPLC_Warp4,  SonPLC_Stop1,  SonPLC_Stop2,  SonPLC_Duck,SonPLC_Balance1,  SonPLC_Balance2,
			SonPLC_Float1, SonPLC_Float2, SonPLC_Float3, SonPLC_Float4, SonPLC_Spring, SonPLC_Hang1,  SonPLC_Hang2,  SonPLC_Leap1,  SonPLC_Leap2,  SonPLC_Push1,
			SonPLC_Push2,  SonPLC_Push3,  SonPLC_Push4,  SonPLC_Surf, SonPLC_BubStand, SonPLC_Death,  SonPLC_Drown,  SonPLC_Burnt, SonPLC_Shrink1, SonPLC_Shrink2,
			SonPLC_Shrink3,SonPLC_Shrink4,SonPLC_Shrink5,SonPLC_Float1, SonPLC_Float3, SonPLC_Injury, SonPLC_GetAir, SonPLC_WaterSlide };




void pcSonic()
{
     Sonic_Index[0]=Sonic_Main;
     Sonic_Index[1]=Sonic_Control;
     Sonic_Index[2]=Sonic_Hurt;
     //Sonic_Index[3]=Sonic_Death;
     //Sonic_Index[4]=Sonic_ResetLevel;
     Sonic_Modes[0]=Sonic_MdNormal;
     Sonic_Modes[1]=Sonic_MdJump;
     Sonic_Modes[2]=Sonic_MdRoll;
     Sonic_Modes[3]=Sonic_MdJump2;
}
//OBJECT TREE

//A) OBJECT CODE ENTRY POINT    - SonicPlayer()
//   A1) OBJECT CODE INIT ROUTINE      (todo describe separate init vals)   - SonicMain()
//   A2) OBJECT CODE CONTROL ROUTINE   (describe a control routine)         - SonicControl()
//   INCLUDES OBJECT DISPLAY, OBJECT RECORD POSTION, AND OBJECT WATER ROUTINES     - SonicDisplay, SonicRecordPosition, SonicWater
//   
//     -- IF CONTROL LOCK THEN
//     A2A) OBJECT CONTROL  (the separate modes basically run different sequences of the objects core functions)
//     runs the proper function based on current object mode..  
//     MODES  normal        
//            jump
//            roll
//            jump2
//     SETS current player animation frame to previously calculated next animation frame
//     ALSO INCLUDES: OBJECT ANIMATE
//                    IF NO CONTROL LOCK THEN OBJECT REACT WITH ITEM
//                    OBJECT MISC CODE (LOOPS)
//                    OBJECT RELOAD GRAPHICS 


void Sonic_Player(object *obj)
{
     //  test if v_debugmode on if so then jump to ..
     //if (v_debuguse)
        //DebugMode();
     v_debuguse = 0;
      
     (*Sonic_Index[player.Routine/2])();
     

}

void Sonic_Main()    //AN OBJECTS MAIN FUNCTION WILL ALWAYS INIT ITS VALUES BEFORE HANDLING CONTROL IF THE OBJECT HAS NOT BEEN INITIALIZED, ROUTINE=0
{
     //this is the function for init sonic's values
     player.Routine+=2;		 //this is 2 in ROM
     player.Height=19;
     player.Width=9;
     player.Map=getMap_Sonic();  //these are the decompressed mappings
     player.Gfx=0x780;      //this is the starting position of sonics tiles in vram
     player.Priority=2;     
     player.ActionWidth=0x18;
     player.Render=4;        //bit 3 only set
     
     //0 	$01 	This is the horizontal mirror flag. If set, the object will be flipped on its horizontal axis.
     //1 	$02 	This is the vertical mirror flag.
     //2/3 	$04/$08 These are the coordinate system. If 0, the object will be positioned by absolute screen coordinates. This is used for things like the HUD and menu options. If 1, the object will be positioned by the playfield coordinates, i.e. where it is in a level. If 2 or 3, the object will be aligned to the background somehow (perhaps this was used for those MZ UFOs).
     //4 	$10 	This is the assume height flag. The object will be drawn if it is vertically within x pixels of the screen where x is #$20 if this flag is clear or $16(a0) if it is set.
     //5 	$20 	This is the raw mappings flag. If set, just 5 bytes will be read from the object's mappings offset when the BuildSprites routine draws the object, and these will be interpreted in the normal manner to display a single Genesis sprite. This format is used for objects such as breakable wall fragments.
     //6 	$40 	This is Sonic's "Ride B" flag
     //7 	$80 	This is the on-screen flag. It will be set if the object is on-screen, and clear otherwise. 

     v_sonspeedmax=0x600;
     v_sonspeedacc=0xC;
     v_sonspeeddec=0x80;
     Sonic_Control();        //we continue on with routine 2, controlling sonic
}
     
     
void Sonic_Control()  //THIS IS WHEN ROUTINE = 2
{
     //if (f_debugmode ||  bit for b in v_jpadpress)
     //{
     //v_debuguse=1;
     //f_lockctrl=0;
     //}
     //else
     //{
     //loc_12c58:
     if (f_lockctrl==0)    //if controls are not locked due to ending sequence
     {
        v_jpadhold2=v_jpadhold1;                    //copy into main hold buffer
        v_jpadpress2=v_jpadpress1;                  //copy into main press buffer
     } 
     //0	$01	Orientation. Clear is left and set is right.
     //1	$02	Set if Sonic is in the air (jump counts).
     //2	$04	Set if jumping or rolling.
     //3	$08	Set if Sonic isn't on the ground but shouldn't fall. (Usually when he is on a object that should stop him falling, like a platform or a bridge.)
     //4	$10	Set if jumping after rolling.
     //5	$20	Set if pushing something.
     //6	$40	Set if underwater.
     //7	$80	Unused.

     if ((f_lockmulti & 1) == 0)  //main flag set to lock controls, lock Sonic's position and animation
     {
         byte modeIndex = (player.Status & 6)>>1;     //get bits 1 &2  (76543210), bit 0 skipped because mode 0 is initialization
         (*Sonic_Modes[modeIndex])();               //run the proper sonic mode routine    
     }
     
     Sonic_Display();
     //Sonic_RecordPosition();
     //Sonic_Water();
     
     /*used to check most recent angle during a balance*/
     player.Variables[14]=(byte)v_anglebuffer;
     player.Variables[15]=(byte)FFFFF76A;

     if (f_wtunnelmode != 0 && player.Anim == 0)
           player.Anim=player.NextAni;
     
     Sonic_Animate();
     
     if (f_lockmulti>=0)        //if main flag not set to lock controls
     {
         ReactToItem();
     } 
     Sonic_Loops();
     Sonic_LoadGfx();
}

bool donejump=false;

//  ========= OBJECT MODES ========
void Sonic_MdNormal()
{    
     donejump=false;
     Sonic_Jump();
     if (!donejump)
     {
     Sonic_SlopeResist();
     Sonic_Move();
     
     Sonic_Roll();
     Sonic_LevelBound();
     SpeedToPos(&player);
     Sonic_AnglePos();
     Sonic_SlopeRepel();
     }
}

void Sonic_MdJump()
{
     Sonic_JumpHeight();
     Sonic_JumpDirection();
     Sonic_LevelBound();
     ObjectFall(&player);
     if ((player.Status&64)==64)         //bit 6, underwater
        player.VelocityY=player.VelocityY-0x28;
     Sonic_JumpAngle();
     Sonic_Floor();
}

void Sonic_MdRoll()
{
     Sonic_Jump();
     Sonic_RollRepel();
     Sonic_RollSpeed();
     Sonic_LevelBound();
     SpeedToPos(&player);
     Sonic_AnglePos();
     Sonic_SlopeRepel();
}

void Sonic_MdJump2()
{
     Sonic_JumpHeight();
     Sonic_JumpDirection();
     Sonic_LevelBound();
     ObjectFall(&player);
     if ((player.Status&64)==64)         
        player.VelocityY=player.VelocityY-0x28;
     Sonic_JumpAngle();
     Sonic_Floor();
}

//==============CORE OBJECT FUNCTIONS=================
void Sonic_Jump()
{
     byte tempjpad=v_jpadpress2&btnABC;
     if (tempjpad==0) { return; }                     // if A B or C IS NOT PRESSED THEN DONT JUMP... 
     
     byte angle=player.Angle+0x80;                   //angle=d0
     
     signed short landHeight;				     //one of 4 routines called from sub_14d48 returns this value 
     
     //here starts the code of sub_14d48..., in main.asm (calculates room overhead of sonic) right after WalkSpeed
     v_anglebuffer=(signed char)angle;                            //angle=d0
     FFFFF76A=(signed char)angle;
     
     angle=(angle+0x20)&0xC0;
     
     if (angle == 0x40)
          Sonic_CheckLeftCeiling(landHeight,angle);
     else if (angle == 0x80)
          Sonic_CheckCeiling(landHeight,angle);
     else if (angle == 0xC0)
          Sonic_CheckRightCeiling(landHeight,angle);
     else 
          Sonic_CheckFloor(landHeight,angle);
     //-----------------------------------------------------------//
     
     if (landHeight>=6)               //value returned from the proper jumping function at sonic angle
     {
        //When Sonic is standing upon the ground, and you press the jump button, Y speed is set to -6.5 (jmp).
        word jumpSpeed=0x680;
        if ((player.Status&64)==64)   //sonic underwater?
                jumpSpeed=0x380;                   
        byte jumpAngle=player.Angle-0x40;
        
 
        //------------------------------------
        //Jumping is also affected by the angle Sonic is at when he does it. He can't simply set Ysp to jmp -
        //he needs to jump away from the angle he's standing on. Instead, both Xsp and Ysp must be set to jmp,
        // using cos() and sin() to get the right values.

        //More pseudo-code:

        //Xsp -= jmp*sin(angle);
        //Ysp -= jmp*cos(angle);

        //...jmp here being the approximate pixel distance to cover (at current angle) - returned by the respective four modes function
        //    which affects velocity x & y values
        //    which in turn both affect sonic's x/y position

        signed short sine, cosine;
        CalcSine(jumpAngle, sine, cosine);
        
        signed short scaledCosine=(cosine*jumpSpeed)>>8;         
        player.VelocityX+=scaledCosine;                 //make sonic jump
        
        signed short scaledSine=(sine*jumpSpeed)>>8;
        player.VelocityY+=scaledSine;                  //make sonic jump
        //-------------------------------------

        player.Status=player.Status | 2;                                //set bit 1   (sonic is in the air due to a jump)
        player.Status=player.Status-(player.Status&32);  //clear bit 5 (sonic not pushing anything)
     
        //Disturbingly, the computer checks to see if you press the jump button before moving Sonic. 
        //If you do press the jump button, it exits the rest of the cycle - so Sonic doesn't move at all during the step in which you jump, 
        //vertically or horizontally. This is lame, because X speed isn't lost, so he should continue to move. 
        //This flaw can be buffed out in a new engine.

        //A.K.A STACK IS PUSHED BACK A LONG, 
        //THE RETURN ADDRESS NOW REFERS TO THE CODE RIGHT AFTER THE CALL TO THE CURRENT MODE HANDLING SUBROUTINE..
        //THIS SKIPS THE REST OF HANDLING FOR THE CURRENT MODE (so no values are replaced from this point, the mode has changed to jumping)
        //__asm__ __volatile__("leave");
        donejump = true;
      
        player.Variables[20]=1;
        player.Variables[16]=0;
        
        //SFX_JUMP SOUND
        player.Height=0x13;
        player.Width=9;
        if ((player.Status&4)==4)                         //if bit 2 is set (sonic in a ball due to ROLL)
        {
               player.Status=player.Status | 16; //bit 4	        //set bit 4    (Flag for sonic jumping AFTER rolling)
        }
        else						//else we manually modify object parameters to fit ROLLING
        {
            player.Height=0xE;    
            player.Width=7;
            player.Anim=id_Roll;
            player.Status=player.Status | 4;
            player.Y+=5;
        }
     }
     
     
}    




#define flashtime 0x30		//; time between flashes after getting hit
#define invtime 0x32		//; time left for invincibility
#define shoetime 0x34		//; time left for speed shoes
     

//todo order 1
void Sonic_Display()
{
 //Sonic_Display:
 //move.w	flashtime(a0),d0
        word flashtimeBuf=getobjvariableword(flashtime,objects[0]);

	//beq.s	@display
	if (flashtimeBuf!=0)                              //if sonic not done flashing
	{
            //subq.w	#1,flashtime(a0)
            subobjvariableword(flashtime,objects[0],1);           //subtract 1 from flash count
            
            //lsr.w	#3,d0
            //bcc.s	@chkinvincible
            if (flashtimeBuf % 8 !=0)                    //then only display sprite
        
	        //@display:
               DisplaySprite(&objects[0]);                //for every 8 counts
         }
         else { DisplaySprite(&objects[0]); }             //otherwise display entirely
         
	//@chkinvincible:
	//tst.b	(v_invinc).w	; does Sonic have invincibility?
        if (v_invinc!=0 && getobjvariableword(invtime,objects[0])!=0)    //if sonic is invincible and has time remaining on invincibility counter   
        {    
            //beq.s	@chkshoes	; if not, branch
            //tst.w	invtime(a0)	; check	time remaining for invinciblity
    	    //beq.s	@chkshoes	; if no	time remains, branch
    	    //subq.w	#1,invtime(a0)	; subtract 1 from time
    	    subobjvariableword(invtime,objects[0],1);                  //then decrease invincibililty counter
            
            //bne.s	@chkshoes
	    if (getobjvariableword(invtime,objects[0])==0)             //if time up on invincibility counter
	    {
                                                              
                //tst.b	(f_lockscreen).w
        	if (f_lockscreen && v_air<0xC)                //if air is still remaining underwater (not counting down yet) and screen is locked
                {
                    //bne.s	@removeinvincible
            	    //cmpi.w	#$C,(v_air).w
            	    //bcs.s	@removeinvincible
            	    //moveq	#0,d0
            	    //move.b	(v_zone).w,d0
            	    byte zoneBuf=v_zone;
            		
            	    #define id_LZ 1
                    //cmpi.w	#(id_LZ<<8)+3,(v_zone).w ; check if level is SBZ3
            	    if (v_zone==(id_LZ<<8)+3)
                        zoneBuf=5;
                    //bne.s	@music
            	    //moveq	#5,d0		; play SBZ music
            
            	    //@music:
            	    //lea	(MusicList2).l,a1
            	    //move.b	(a1,d0.w),d0
            	    //jsr	(PlaySound).l	; play normal music
                    //PlaySound(MusicList2[zoneBuf]);            //then play the proper zone music
                }
            
                //@removeinvincible:
        	    //move.b	#0,(v_invinc).w ; cancel invincibility
                v_invinc=0;
             }
          }    
	   
            //@chkshoes:
	    //tst.b	(v_shoes).w	; does Sonic have speed	shoes?
	    //beq.s	@exit		; if not, branch
	    if (v_shoes && getobjvariableword(shoetime,objects[0])!=0)
	    {
            //tst.w	shoetime(a0)	; check	time remaining
	    //beq.s	@exit

            
            //subq.w	#1,shoetime(a0)	; subtract 1 from time
	    subobjvariableword(shoetime,objects[0],1);
            
            //bne.s	@exit
            if (getobjvariableword(shoetime,objects[0])==0)
            {
               //move.w	#$600,(v_sonspeedmax).w ; restore Sonic's speed
	       v_sonspeedmax=0x600;
        
               //move.w	#$C,(v_sonspeedacc).w ; restore Sonic's acceleration
	       v_sonspeedacc=0xC;
		       
               //move.w	#$80,(v_sonspeeddec).w ; restore Sonic's deceleration
	       v_sonspeeddec=0x80;
		       
               //move.b	#0,(v_shoes).w	; cancel speed shoes
	       v_shoes=0;
		       
               //move.w	#$E3,d0
	       //jmp	(PlaySound).l	; run music at normal speed
               //PlaySound(0xE3);
            }
         }   
	//@exit:
	//	rts	*/
              
     
}
 //slope resist move roll
//todo 2
void Sonic_SlopeResist()			//ACCUMULATE sonic's INERTIA with sine of current angle, 
{						//GIVEN angle value says sonic is on a slope
         //
        //Sonic_SlopeResist:			; XREF: Obj01_MdNormal
        //     move.b	obAngle(a0),d0
	//     addi.b	#$60,d0
	byte angle=objects[0].Angle+0x60;           //the math here adds 3/8 of a full anti-clockwise 360 deg rotation                                                     V------|
		                                    //angles then in the range of 0x00-0x7F range equate to range 0x60-0xDF, splits into 0x60-0x7F,0x80-0x9F,0xA0-0xBF,0xC0-0xDF  |
        //cmpi.b	#$C0,d0                     //            in the range of 0x80-0xFF range equate to range 0xE0-0xFF - 0-0x5F,    0xE0-0xFF,0x00-0x1F,0x20-0x3F,0x40-0x5F  |
	if (angle>=0xC0)                            //                            adding 0xC0 (-64):results in negative on these ranges:               ^---------^----------------|                           
        //bcc.s	locret_13508                        //                                                 which correspond to orig angles 0xA0-0xBF,0xC0-0xDF,0x60-0x7F                                                
		return;
		        
        signed short sine,cosine;
        //move.b	obAngle(a0),d0
	//jsr	(CalcSine).l
	CalcSine(objects[0].Angle,sine,cosine);
		
        //muls.w	#$20,d0
        //asr.l	#8,d0
	//By this point, Sonic ought to be able to handle any hills with an accurate velocity. 
	//But he still needs to be slowed when going uphill, and sped up when up going downhill.
	//Fortunately, this is simple to achieve - with something called the Slope Factor (slp). 
	//Just add slp*sin(angle) to Gsp at the beginning of every step. 
	//The value of slp is always 0.125 ($0020) when running
	signed short scaledSine=(sine*0x20)/256;

        //tst.w	obInertia(a0)
	//Note: In Sonic 1, it appears that slp doesn't get added if Sonic is stopped, and in his standing/waiting cycle
	if (player.Inertia==0) { return; }
		
        //beq.s	locret_13508
	//bmi.s	loc_13504
	if (player.Inertia<0) { player.Inertia=player.Inertia+scaledSine; }
	else
        {
            //tst.w	d0
            //beq.s	locret_13502
            if (scaledSine==0) { return; }
	    else { player.Inertia=player.Inertia+scaledSine; }
            //add.w	d0,obInertia(a0) ; change Sonic's inertia
        }       
//locret_13502:
//		rts	
//; ===========================================================================

//loc_13504:
//		add.w	d0,obInertia(a0)

//locret_13508:
//		rts
}

word sonspeedmax,sonspeedacc,sonspeeddec;

//todo 3
void Sonic_Move()                
{
   
//; ---------------------------------------------------------------------------
//; Subroutine to	make Sonic walk/run
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


//Sonic_Move:				; XREF: Obj01_MdNormal
//		move.w	(v_sonspeedmax).w,d6
//		move.w	(v_sonspeedacc).w,d5
//		move.w	(v_sonspeeddec).w,d4
        sonspeedmax=v_sonspeedmax;
        sonspeedacc=v_sonspeedacc;
        sonspeeddec=v_sonspeeddec;

	//tst.b	(f_jumponly).w
	//bne.w	loc_12FEE
	if (f_jumponly==0)
	{
            //tst.w	$3E(a0)
	    if (getobjvariableword(0x3E,objects[0])!=0)        //control lock timer, Set to lock left and right controls after hitting a spring or running down a slope.
               Sonic_ResetScr();
            else
            {
               //bne.w	Sonic_ResetScr
	       //btst	#bitL,(v_jpadhold2).w ; is left being pressed?
	       if ( (v_jpadhold2 & (1 << bitL)) == (1<<bitL) )
                  Sonic_MoveLeft();
               //beq.s	@notleft	; if not, branch
	       //bsr.w	Sonic_MoveLeft

               //@notleft:
	       //btst	#bitR,(v_jpadhold2).w ; is right being pressed?
	       if ( (v_jpadhold2 & (1 << bitR)) == (1<<bitR) )
                  Sonic_MoveRight();
               //beq.s	@notright	; if not, branch
	       //bsr.w	Sonic_MoveRight

               //@notright:
	       //move.b	obAngle(a0),d0
	       //addi.b	#$20,d0
	       //andi.b	#$C0,d0		; is Sonic on a	slope?
	       if ((objects[0].Angle+0x20)&0xC0 != 0 || (objects[0].Inertia!=0))    //if sonic is on a slope, (aka NOT angles 0x20:0xE0[315 deg:45 deg], or ONLY angles > 45deg | <= -45deg)
                  Sonic_ResetScr();
    		//bne.w	Sonic_ResetScr	; if yes, branch
    		//tst.w	obInertia(a0)	; is Sonic moving?
    		//bne.w	Sonic_ResetScr	; if yes, branch
    		
	       else                                                               //if sonic is not on a slope  
	       {
	 	    //bclr	#5,obStatus(a0)
    		    objects[0].Status=objects[0].Status-(objects[0].Status&32); //sonic no longer pushing anything
	       
                    //move.b	#id_Wait,obAnim(a0) ; use "standing" animation
	            objects[0].Anim=id_Wait;        
	            
                    //btst	#3,obStatus(a0)
	            if ((objects[0].Status&8)!=8)                                 //if bit 3 not set (isnt on the ground but shouldnt fall)
                       Sonic_Balance();
                       //beq.s	Sonic_Balance
	            else
	            {
                       //moveq	#0,d0
	               //move.b	$3D(a0),d0
	               //lsl.w	#6,d0
	               //lea	(v_objspace).w,a1
	               //lea	(a1,d0.w),a1
                       //byte lookobjindex=player.Variables[0x3D-0x28];             //player variable 0x3D = 0ST index of object currently being stood on
	               //object *lookobj=&objects[lookobjindex];
	               
                       //tst.b	obStatus(a1)
	               //if (lookobj->Status > 80)   
                          //Sonic_LookUporDuck();
               
	               /*
	               else
	               {
			       //bmi.s	Sonic_LookUp
    		               //moveq	#0,d1
    		               //move.b	obActWid(a1),d1
    		               byte obActWid=lookobj->ActionWidth;
			   
			       //move.w	d1,d2
			       //add.w	d2,d2
    		               //subq.w	#4,d2
    		               word obActWidBuf=(obActWid*2)-4;
	   
			       //add.w	obX(a0),d1
    		               //sub.w	obX(a1),d1
    		               obActWid=obActWid+objects[0].X-lookobj->X;
			       //cmpi.w	#4,d1
    	
			       //blt.s	loc_12F6A
    		               if (obActWid<4)
    		               {
			            objects[0].Status=objects[0].Status|1;
    		                    objects[0].Anim=id_Balance;
			            Sonic_ResetScr();
	                       }
	                       else
	                       {
	                           //cmp.w	d2,d1
    		                   if (obActWid<obActWidBuf)
    		                      Sonic_LookUporDuck();
		                   else                       //loc_12F5A basically follows the 1st path of a quicker Sonic_Balance
		                   {
    		                        objects[0].Status=objects[0].Status-(objects[0].Status&1);
    		                   	objects[0].Anim=id_Balance;
	                                Sonic_ResetScr();
	                           }
	                           //bge.s	loc_12F5A
    		                   //bra.s	Sonic_LookUp
	                   }
	
	               }
	               */
                       Sonic_LookUporDuck();
                    }
               }
            }
       }
              
      //finally player can have new x & y velocity based on sine & cosine of angle & NEW inertia scalar
      //loc_12FEE:   (CALCULATE X & Y VELOCITIES BASED ON SINE AND COSINE OF CURRENT ANGLE)
      //called traction in sonic 2 dissasembly..

      //move.b	obAngle(a0),d0
      signed char obAngle = player.Angle; 

      //jsr	(CalcSine).l
      signed short sine, cosine;
      CalcSine(obAngle,sine,cosine);
      
      //muls.w	obInertia(a0),d1
      signed long scaledCosine = cosine * objects[0].Inertia;
 
      //asr.l	#8,d1
      signed long newXVelocity=scaledCosine>>8;
      
      //move.w	d1,obVelX(a0)
      objects[0].VelocityX=newXVelocity;

      //muls.w	obInertia(a0),d0 
      signed long scaledSine = sine * objects[0].Inertia;
      
      //asr.l	#8,d0
      signed long newYVelocity=scaledSine>>8;
      //if (scaledSine < 0) { newYVelocity = newYVelocity | 0xFF000000; }
      
      //move.w	d0,obVelY(a0)
      objects[0].VelocityY=newYVelocity;

      //loc_1300C:
      Sonic_StopAtWalls();


}//; End of function Sonic_Move

void Sonic_StopAtWalls()
{
   //NOTE: FOR ANGLES
//return (256-hex_angle)*1.40625;    FROM SONIC PHYSICS GUIDE
              
//loc_1300C:    (2 RESTRICTIONS HERE, SONIC DOES NOT MOVE DUE TO THIS FUNCTION IF MET)
//              stop Sonic from running through walls that meet the ground


      //move.b	obAngle(a0),d0
      //addi.b	#$40,d0
      if (player.Angle>0xC0) { return; }        //if sonic angle not 90-270 range, upside down?      //bmi.s	locret_1307C
      
      //move.b	#$40,d1
      signed short angAdd=0x40;
      if (objects[0].Inertia==0) { return; }     //if sonic has no inertia
      //tst.w	obInertia(a0)
      //beq.s	locret_1307C


      //bmi.s	loc_13024
      if (objects[0].Inertia>0)               //for positive inertia we need to rotate right as sonic is moving right
          angAdd=-angAdd;
           
   
        //====at this point if sonic moving and in left wall/right wall/ceiling mode====
 
        //loc_13024:
	//move.b	obAngle(a0),d0
	//add.b	d1,d0
        signed char horizAngle=player.Angle+angAdd;   //the proper adjustments to grab a 90 degree rotated version of sonic's angle in the direction of movement (i.e. left or right)
        
        //move.w	d0,-(sp)
	//bsr.w	Sonic_WalkSpeed               
	//move.w	(sp)+,d0
	
	//calculate space between Sonic's future position at current x/y velocity and wall 
        //thinking a step ahead by taking into account the soon shift in position caused by current X&Y velocities
        signed short wallDist = Sonic_WallDistSpeed(horizAngle);         //this function called with angle PERPENDICULAR to sonic's spine


        //d1 = distance between sonic and solid area referred to by angle
	//tst.w	d1           
	if (wallDist >= 0) {return;}                //if sonic would not be touching the solid area at current velocities, then no need to worry      
        //bpl.s	locret_1307C
	
	//otherwise at these velocities sonic would either touch or pass up completely the solid area 
       
        //asl.w	#8,d1                          
	signed short wallDistScale = wallDist * 256;    //scale the amount to push back by for values that would pass up the solid area                           
		
        //addi.b	#$20,d0
	//andi.b	#$C0,d0
	byte quadrant = (horizAngle + 0x20) & 0xC0;
		
	if (quadrant == 0)
	{
            //beq.s	loc_13078
            //loc_13078:
	    //add.w	d1,obVelY(a0)
            objects[0].VelocityY = objects[0].VelocityY + wallDistScale;        //scale back the current velocities in the Y direction, but do not slow down
            //locret_1307C:
            //rts	
		
        }
        else if (quadrant == 0x40)
        {
            //cmpi.b	#$40,d0
            //loc_13066:
            //sub.w	d1,obVelX(a0)            objects[0].VelocityX = objects[0].VelocityX - wallDistScale;  //scale back the current velocities in the X direction (slows frame rate)
              
            //bset	#5,obStatus(a0)
    	    objects[0].Status = objects[0].Status | 32;            //sonic is 'pushing' against the wall
    		  
            //move.w	#0,obInertia(a0)
    	    objects[0].Inertia = 0;                              //stop sonic at the wall, (a.k.a not moving)
	    //rts	
            //; ===========================================================================
	}
        else if (quadrant == 0x80)
        {
            //cmpi.b	#$80,d0
            //beq.s	loc_13060
            //loc_13060:
	    //sub.w	d1,obVelY(a0)
            objects[0].VelocityY = objects[0].VelocityY - wallDistScale;        //scale back the current velocities in the Y direction, but do not slow down
            //rts	
            //; ===========================================================================
        }
        else
        {
              //add.w	d1,obVelX(a0)
              objects[0].VelocityX=objects[0].VelocityX + wallDistScale;  //scale back the current velocities in the X direction (slows frame rate)
              
              //bset	#5,obStatus(a0)
    	      objects[0].Status = objects[0].Status | 32;            //sonic is 'pushing' against the wall
    		  
              //move.w	#0,obInertia(a0)
              objects[0].Inertia = 0;                              //stop sonic at the wall, (a.k.a not moving)
        }
        //       rts	
        //; ===========================================================================
}

void Sonic_ResetScr()          //used by Sonic_Move, RESETS LOOKSHIFT VALUE WHEN NOT AT ITS INITIAL VALUE (OR WHEN UP/DOWN NOT PRESSED)
{			       //                    RESETS SONIC INERTIA WHEN LEFT/RIGHT IS NOT PRESSED
     //cmpi.w	#$60,(v_lookshift).w ; is screen in its default position?
     if (v_lookshift!=0x60)
     {
        //beq.s	loc_12FC2	; if yes, branch         all calls to Sonic_ResetScr eventually end up here
    	//bcc.s	loc_12FBE
        if (v_lookshift>0x60)
        {
           //loc12FBE:
    	   //subq.w	#2,(v_lookshift).w ; move screen back to default
           v_lookshift=v_lookshift-2;
        }
        else
    	{
           //addq.w	#4,(v_lookshift).w ; move screen back to default
           v_lookshift=v_lookshift+4;
        }
     }
    

     //loc_12FC2:
     //move.b	(v_jpadhold2).w,d0
     //andi.b	#btnL+btnR,d0	; is left/right	pressed?

     //AT THIS POINT IF L OR R IS NOT PRESSED, INERTIA IS RESET WITH SONSPEEDACC VALUES, UNLESS V_JUMPONLY FLAG
     if ((v_jpadhold2 & (btnL+btnR)) == 0)
     {
        //bne.s	loc_12FEE	; if yes, branch
	//move.w	obInertia(a0),d0
	signed short obInertia=objects[0].Inertia;
	
        //beq.s	loc_12FEE
	if (obInertia != 0)		
	{
           if (obInertia >= 0)
	   {
		//bmi.s	loc_12FE2
		//sub.w	d5,d0
	        obInertia=obInertia-sonspeedacc;
		
                //bcc.s	loc_12FDC
                if (obInertia<0)
		    obInertia=0;
	            //move.w	#0,d0

	        //loc_12FDC:
	        player.Inertia=obInertia;
		//move.w	d0,obInertia(a0)           }
	   //bra.s	loc_12FEE
	   //; ===========================================================================
	   else
	   {
			
		
	        //loc_12FE2:
	        //add.w	d5,d0
	        obInertia=obInertia+sonspeedacc;
		
                //bcc.s	loc_12FEA
		if (obInertia>0)
		   obInertia=0;
		   //move.w	#0,d0
		
		//loc_12FEA:
		//move.w	d0,obInertia(a0)
		player.Inertia=obInertia;
	   }
	}
     }  
}

void Sonic_LookUporDuck()         //used by Sonic_Move
{
   //Sonic_LookUp:
	//btst	#bitUp,(v_jpadhold2).w ; is up being pressed?
	if ((v_jpadhold2&(1<<bitUp))==(1<<bitUp))
        {
          //beq.s	Sonic_Duck	; if not, branch
	      //move.b	#id_LookUp,obAnim(a0) ; use "looking up" animation
          objects[0].Anim=id_LookUp;
          	
          //cmpi.w	#$C8,(v_lookshift).w
	      if (v_lookshift!=0xC8)
              {
            //---- vvvv beq.s	loc_12FC2 vvvv ----//
	        //addq.w	#2,(v_lookshift).w
	        v_lookshift=v_lookshift+2;
              }

             //beq.s	loc_12FC2
        }
        else if ((v_jpadhold2&(1<<bitDn))==(1<<bitDn))
        {
           //Sonic_Duck:
           //btst	#bitDn,(v_jpadhold2).w ; is down being pressed?
    
	       //beq.s	Sonic_ResetScr	; if not, branch
	       //move.b	#id_Duck,obAnim(a0) ; use "ducking" animation
	       objects[0].Anim=id_Duck;
	       
               //cmpi.w	#8,(v_lookshift).w
	       if (v_lookshift!=8)
               {
                  //beq.s	loc_12FC2
	          //subq.w	#2,(v_lookshift).w
                  v_lookshift=v_lookshift-2;
                  //bra.s	loc_12FC2
               }
           
        }
        else   
            Sonic_ResetScr();
}

void Sonic_Balance()
{
     //Sonic_Balance:
    //ObjFloorDist();
    //jsr	ObjFloorDist
    word d1=0xB;
    if (d1<0xC)
         Sonic_LookUporDuck();
    else
    {
       //cmpi.w	#$C,d1
	   //blt.s	Sonic_LookUp
	   //cmpi.b	#3,$36(a0)
       if (player.Variables[14]==3)
       {
        //bne.s	loc_12F62
        //loc_12F5A:
	     //bclr	#0,obStatus(a0)
	      objects[0].Status=objects[0].Status-(objects[0].Status&1);
         //bra.s	loc_12F70
       }
       else
       {
            //; ===========================================================================
            //loc_12F62:
            //cmpi.b	#3,$37(a0)
	    if (player.Variables[15]==3)
            {
		     //loc_12F6A:
		     //bset	#0,obStatus(a0)
		        objects[0].Status=objects[0].Status|1;
            }
        }
  	    
        //loc_12F70:
        //move.b	#id_Balance,obAnim(a0) ; use "balancing" animation
	objects[0].Anim=id_Balance;
        Sonic_ResetScr();
        //; ===========================================================================
    }
}

     

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


//Sonic_MoveLeft:				; XREF: Sonic_Move
void Sonic_MoveLeft()
{
     
       //move.w	obInertia(a0),d0
       signed short newInertia=player.Inertia;
		
       //beq.s	loc_13086
       //bpl.s	loc_130B2

       if (newInertia<=0)			              //if sonic is idle (not moving left or right)
       {
           //loc_13086:
           //bset	#0,obStatus(a0)
	   //bne.s	loc_1309A
	   byte oldstatus=player.Status;			 //Status bit 0: orientation (0: left, 1: right/idle)
	   player.Status=player.Status|1;			 //change orientation to right/idle, as we are NOT moving left
        
           if ((oldstatus&1)!=1)				 //if sonic was already moving left
           {
              player.Status=player.Status-(player.Status&32);	    //then he cannot be pushing something (Status bit 5)
              //bclr	#5,obStatus(a0)				
              //move.b	#1,obNextAni(a0)
              player.NextAni=1;					    //next animation frame in the walking sequence...
           }
           
            //loc_1309A:
            //sub.w	d5,d0
	    newInertia=newInertia-sonspeedacc;   		 //calculate new Inertia by subtracting accel value (negatively for moving left)
            
            //move.w	d6,d1
            //neg.w	d1
	    signed short maxCompare=-sonspeedmax;                 //grab the maximum that this value can be updated (in the left direction)
		    
            //cmp.w	d1,d0
            //bgt.s	loc_130A6
            if (newInertia <= maxCompare)			    //if it exceeds the max value
            {  
               //move.w	d1,d0
               newInertia=maxCompare;				    //reset it back to the max
            }
            //loc_130A6:
            //move.w	d0,obInertia(a0)
            player.Inertia=newInertia;                          //set new Inertia
            
            //move.b	#id_Walk,obAnim(a0) ; use walking animation
            player.Anim=id_Walk;				//use walking animation
		    
       }     //rts
       else if (newInertia >  0)			        //otherwise if sonic was moving right..
       {	
             //loc_130B2:				    ; XREF: Sonic_MoveLeft
	     //sub.w	d4,d0
	     newInertia=newInertia-sonspeeddec;		        //calculate new inertia by subtracting decel value from current inertia (negatively for now moving left)
		     
             //bcc.s	loc_130BA
             if (newInertia < 0)				   //if this is enough to pull sonic to the left (negative)
	     {
                 //move.w	#-$80,d0
                 newInertia=-0x80;				   //inertia is to be set to a minimum of -0x80 
             }
             //loc_130BA:
	     //move.w	d0,obInertia(a0)                  
	     player.Inertia=newInertia;                        //set new Inertia
		                                       // ;d0 originally holds sonic inertia, a WORD
             //move.b	obAngle(a0),d0		          ;BUT the lower half of that word is now replaced with 
	     //addi.b	#$20,d0				  ;object angle & 0xc0 which 
	     //andi.b	#$C0,d0				  ;im pretty sure this yields direction?
	     byte walkAngle=(player.Angle+0x20)&0xC0;	       //calculate quadrant sonic in
		     
             //bne.s	locret_130E8
	     if (walkAngle == 0 )			  //sonic mostly upright
             {
                 //cmpi.w	#$400,d0
		 if ( newInertia >= 0x400)   //if already moving fast enough right down a slope
		 {
                    //blt.s	locret_130E8
                    
                    //move.b	#id_Stop,obAnim(a0) ; use "stopping" animation
		    player.Anim=id_Stop;				   //then just stop because the purpose is to move LEFT
		            
                    //bclr	#0,obStatus(a0)
		    player.Status = player.Status-(player.Status&1);       //change orientation
                    
                    //sfx	sfx_Skid	; play stopping sound
                    //sfx(sfx_Skid);
                 }
            }
       }
//locret_130E8:
//		rts	
//; End of function Sonic_MoveLeft
}

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


//Sonic_MoveRight:			; XREF: Sonic_Move
void Sonic_MoveRight()
{
    //move.w	obInertia(a0),d0		
    signed short newInertia = player.Inertia;
        
    //bmi.s	loc_13118
   
    if (newInertia >= 0)
    {
        //bclr	#0,obStatus(a0)
        byte oldstatus=player.Status;
        player.Status=player.Status-(player.Status&1);
           
        //beq.s	loc_13104        if ((oldstatus&1)!=0)
        {
            //bclr	#5,obStatus(a0)
            player.Status=player.Status-(player.Status&32);
		
	    //move.b	#1,obNextAni(a0)
            player.NextAni=1;
        }               

//loc_13104:
        //add.w	d5,d0        newInertia=newInertia+sonspeedacc;
		   
        //cmp.w	d6,d0
        if (newInertia >= sonspeedmax)
        {
            //blt.s	loc_1310C
            //move.w	d6,d0
            newInertia=sonspeedmax;
        }
        //loc_1310C:
	//move.w	d0,obInertia(a0)
	player.Inertia=newInertia;
        
        //move.b	#id_Walk,obAnim(a0) ; use walking animation
        player.Anim=id_Walk;
		       
	     //rts
    }
    else
    {	
        //; ===========================================================================
        //loc_13118:				; XREF: Sonic_MoveRight
    
        //add.w	d4,d0
        newInertia=newInertia+sonspeeddec;
    		
        //bcc.s	loc_13120
        //move.w	#$80,d0
        if (newInertia<0)
           newInertia=0x80;
               
        //loc_13120:
    	//move.w	d0,obInertia(a0)
    	player.Inertia=newInertia;
    		
        //move.b	obAngle(a0),d0
    	//addi.b	#$20,d0
    	//andi.b	#$C0,d0
    	byte walkAngle=((player.Angle + 0x20)&0xC0);
    		
        //bne.s	locret_1314E
    	if (walkAngle==0)
    	{
            //cmpi.w	#-$400,d0
            if ( newInertia <= -0x400)
            {
                //bgt.s	locret_1314E
    	        //move.b	#id_Stop,obAnim(a0) ; use "stopping" animation
    		player.Anim=id_Stop;
    		         
                //bset	#0,obStatus(a0)
    		player.Status=player.Status|1;
    		         
                    //sfx(sfx_Skid);	//; play stopping sound
                
           }
    //locret_1314E:
    //		rts	
    //; End of function Sonic_MoveRight
     //     */       
        }    
    }
}    

signed short Sonic_WallDistSpeed(byte angle)
{
        //Sonic_WalkSpeed:			; XREF: Sonic_Move
	//move.l	obX(a0),d3
	long obXdec=objects[0].Xdec;
	
	//move.l	obY(a0),d2
	long obYdec=objects[0].Ydec;
	
	//move.w	obVelX(a0),d1
	//ext.l	d1
	//asl.l	#8,d1
        signed short obVelX = player.VelocityX;

        //ext.l	d0
        //asl.l	#8,d0
        signed long shiftX = obVelX << 8;

        //add.l	d0,d1
        long newXdec = obXdec + shiftX;
	
	//move.w	obVelY(a0),d1
        signed short obVelY = player.VelocityY;	

	//ext.l	d1
	//asl.l	#8,d1
	signed long shiftY = obVelY << 8;	

	//add.l	d1,d2
	long newYdec = obYdec + shiftY;
	
	//swap	d2
	//swap	d3
	//obY=((obY&0xFF00)>>8)+((obY&0x00FF)<<8);
	//obX=((obX&0xFF00)>>8)+((obX&0x00FF)<<8);	
        word newY = SWAPLONG(newYdec);
        word newX = SWAPLONG(newXdec);

	//move.b	d0,(v_anglebuffer).w
	//move.b	d0,($FFFFF76A).w
	v_anglebuffer=(signed char)angle;
	FFFFF76A=(signed char)angle;

	//move.b	d0,d1
	//addi.b	#$20,d0
	byte oldAngle=angle;
	byte testAngle=angle+0x20;		

	//bpl.s	loc_14D1A
	
	if ((signed char)testAngle < 0)
	{
	   //move.b	d1,d0
	   testAngle = oldAngle;
	
	   //bpl.s	loc_14D14
           if ((signed char)testAngle<0)		
	       //subq.b	#1,d0
	       testAngle=testAngle-1;

	    //loc_14D14:
	    //addi.b	#$20,d0
	    testAngle=testAngle+0x20;
        }
        //bra.s	loc_14D24
//; ===========================================================================
        else
        {  
           //loc_14D1A:
	   //move.b	d1,d0
	   testAngle=oldAngle;

	   //bpl.s	loc_14D20
           if ((signed char)testAngle<0)
               //addq.b	#1,d0
               testAngle=testAngle+1;

	   //loc_14D20:
	   //addi.b	#$1F,d0 
           testAngle=testAngle+0x1F;					
        }
        //loc_14D24:
	//andi.b	#$C0,d0
        testAngle=testAngle&0xC0;		

        signed short wallDist;
	if (testAngle==0)
        {
	    //beq.w	loc_14DF0 (located after Sonic_HitFloor in ROM)

	    //loc_14DF0:				; XREF: Sonic_WalkSpeed
	    //addi.w	#$A,d2
	    word newYBottom = newY + 0xA;

            //lea	(v_anglebuffer).w,a4
	    signed short *v_anglebufferPtr=&v_anglebuffer;
	
            //movea.w	#$10,a3
	    signed short offset=0x10;
        
            //move.w	#0,d6
            word collisionFlags=0;

            //moveq	#$E,d5
	    byte solidnessBit=0xE;
    
            //bsr.w	FindFloor
	    FindFloor(&objects[0], newYBottom, newX, solidnessBit, collisionFlags, wallDist, offset, v_anglebufferPtr);

            //move.b	#0,d2
            signed char defaultAngle = 0;

            //loc_14E0A:				; XREF: sub_14EB4
            //move.b	(v_anglebuffer).w,d3
            byte newAngle = (v_anglebuffer);

            //btst	#0,d3
            //beq.s	locret_14E16
            if ((newAngle & 1)==1)
                //move.b	d2,d3
                newAngle = defaultAngle;

            //locret_14E16:
	    //rts	
            //;
        }
        else if (testAngle==0x80)
	{		
	    //cmpi.b	#$80,d0
	    //beq.w	loc_14F7C

            //loc_14F7C:
	    //subi.w	#$A,d2
            //eori.w	#$F,d2
            word newYBottom = (newY - 0xA) ^ 0xF;

	    //lea	(v_anglebuffer).w,a4
            signed short *v_anglebufferPtr = &v_anglebuffer;

	    //movea.w	#-$10,a3
            signed short offset = -0x10;
	 
            //move.w	#$1000,d6
            word collisionFlags=0x1000;
            
	    //moveq	#$E,d5
            byte solidnessBit=0xE;
 
	    //bsr.w	FindFloor
            FindFloor(&objects[0], newYBottom, newX, solidnessBit, collisionFlags, wallDist, offset, v_anglebufferPtr);
		
            //move.b	#-$80,d2
            signed char defaultAngle = -0x80;

	    //bra.w	loc_14E0A
            //loc_14E0A:				; XREF: sub_14EB4
            //move.b	(v_anglebuffer).w,d3
            byte newAngle = (v_anglebuffer);

            //btst	#0,d3
            //beq.s	locret_14E16
            if ((newAngle & 1)==1)
                //move.b	d2,d3
                newAngle = defaultAngle;

            //locret_14E16:
	    //rts	
            //;

	}
        else 
	{
	    if ((oldAngle & 0x38) == 0) { newY = newY + 8; }

            //andi.b	#$38,d1
            //bne.s	loc_14D3C
	    //addq.w	#8,d2
               
            //loc_14D3C:
	    //cmpi.b	#$40,d0
            if (testAngle == 0x40)
	    {		
		//beq.w	loc_1504A (after HitWallLeft)
                //loc_1504A:
		//subi.w	#$A,d3
		//eori.w	#$F,d3
                word newXRight = (newX - 0xA) ^ 0xF;
 
		//lea	(v_anglebuffer).w,a4
		signed short *v_anglebufferPtr=&v_anglebuffer;

                //movea.w	#-$10,a3
                signed short offset = -0x10;

		//move.w	#$800,d6
                word collisionFlags=0x800;
		
                //moveq	#$E,d5
		byte solidnessBit=0xE;

                //bsr.w	FindWall
                FindWall(&objects[0], newY, newXRight, solidnessBit, collisionFlags, wallDist, offset, v_anglebufferPtr);
		
                //move.b	#$40,d2
                byte defaultAngle = 0x40;
		
                //bra.w	loc_14E0A
                //loc_14E0A:				; XREF: sub_14EB4
                //move.b	(v_anglebuffer).w,d3
                byte newAngle = (v_anglebuffer);

                //btst	#0,d3
                //beq.s	locret_14E16
                if ((newAngle & 1)==1)
                    //move.b	d2,d3
                    newAngle = defaultAngle;

                //locret_14E16:
	        //rts	
                //;
                
            }
            else
            {   
	        //bra.w loc_14EBC
                //loc_14EBC:
		//addi.w	#$A,d3
                word newXRight = (newX + 0xA);

		//lea	(v_anglebuffer).w,a4
		signed short *v_anglebufferPtr = &v_anglebuffer;

                //movea.w	#$10,a3
		signed short offset = 0x10;

                //move.w	#0,d6
                word collisionFlags=0;

		//moveq	#$E,d5
		byte solidnessBit=0xE;

                //bsr.w	FindWall
		FindWall(&objects[0], newY, newXRight, solidnessBit, collisionFlags, wallDist, offset, v_anglebufferPtr);

                //move.b	#-$40,d2
		signed char defaultAngle = -0x40;

                //bra.w	loc_14E0A
                //loc_14E0A:				; XREF: sub_14EB4
                //move.b	(v_anglebuffer).w,d3
                byte newAngle = (v_anglebuffer);

                //btst	#0,d3
                //beq.s	locret_14E16
                if ((newAngle & 1)==1)
                    //move.b	d2,d3
                    newAngle = defaultAngle;

                //locret_14E16:
	        //rts	
                //;

            }
        }
        return wallDist;
}

//; End of function Sonic_WalkSpeed*/


//todo 4
void Sonic_Roll()
{

//; ---------------------------------------------------------------------------
//; Subroutine allowing Sonic to roll when he's moving
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


    //Sonic_Roll:				; XREF: Obj01_MdNormal
    //tst.b	(f_jumponly).w
    //bne.s	@noroll
    if (f_jumponly == 0)
    {
        //move.w	obInertia(a0),d0
        signed short obInertia = player.Inertia;

	//bpl.s	@ispositive
        //neg.w	d0
        if (obInertia < 0) { obInertia = -obInertia; }
		
        //@ispositive:
	//cmpi.w	#$80,d0		; is Sonic moving at $80 speed or faster?
        //bcs.s	@noroll		; if not, branch
        if (obInertia >= 0x80)
        {
            //move.b	(v_jpadhold2).w,d0
            byte holdState = v_jpadhold2;
            
	    //andi.b	#btnL+btnR,d0	; is left/right	being pressed?
            //bne.s	@noroll		; if yes, branch
            //btst	#bitDn,(v_jpadhold2).w ; is down being pressed?
	    //bne.s	Sonic_ChkRoll	; if yes, branch
            if (((holdState & (btnL+btnR)) == 0) && ((v_jpadhold2 & (1<<bitDn))==(1<<bitDn)))
            {
		//Sonic_ChkRoll:
		//btst	#2,obStatus(a0)	; is Sonic already rolling?
                //beq.s	@roll		; if not, branch
		if ((player.Status & 4) != 4)
                {
                    //@roll:
		    //bset	#2,obStatus(a0)
		    player.Status = player.Status | 4;
                    
                    //move.b	#$E,obHeight(a0)
                    player.Height = 0xE;
		    //move.b	#7,obWidth(a0)
                    player.Width = 7;
		    //move.b	#id_Roll,obAnim(a0) ; use "rolling" animation
		    player.Anim = id_Roll;

                    //addq.w	#5,obY(a0)
                    player.Y = player.Y + 5;

		    //sfx	sfx_Roll	; play rolling sound
		    
                    //tst.w	obInertia(a0)                    //bne.s	@ismoving
                    //move.w	#$200,obInertia(a0) ; set inertia if 0
                    if (player.Inertia == 0)
                        player.Inertia = 0x200;

		    //@ismoving:
		    //rts
                }	            } //rts	
        }
    }	
    //@noroll:
    //rts
    //; ===========================================================================
    //; ===========================================================================

} //; End of function Sonic_Roll

void Sonic_LevelBound()
{

//; ---------------------------------------------------------------------------
//; Subroutine to	prevent	Sonic leaving the boundaries of	a level
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


    //Sonic_LevelBound:			; XREF: Obj01_MdNormal; et al

    //move.l	obX(a0),d1
    long obXdec = player.Xdec;

    //move.w	obVelX(a0),d0
    signed short obVelX = player.VelocityX;

    //ext.l	d0
    //asl.l	#8,d0
    signed long shiftX = obVelX << 8;

    //add.l	d0,d1
    long newXdec = obXdec + shiftX;

    //swap	d1
    word newXint = SWAPLONG(newXdec);

    word resetX;
    #define leftBound resetX
    #define rightBound resetX

    //move.w	(v_limitleft2).w,d0
    //addi.w	#$10,d0
    leftBound = v_limitleft2 + 16;

    //cmp.w	d1,d0		; has Sonic touched the	side boundary?
    //bhi.s	@sides		; if yes, branch
    if (leftBound > newXint)
    {
        //@sides:
        //move.w	d0,obX(a0)
        player.X = resetX;

        //move.w	#0,obX+2(a0)
        player.ScreenY = 0;

        //move.w	#0,obVelX(a0)	; stop Sonic moving
        player.VelocityX = 0;

        //move.w	#0,obInertia(a0)
        player.Inertia = 0;
     
        //bra.s	@chkbottom
    }
    else
    {
        //move.w  (v_limitright2).w,d0
	//addi.w	#$128,d0
        rightBound = v_limitright2 + 296;

	//tst.b	(f_lockscreen).w
        //bne.s	@screenlocked
        //addi.w	#$40,d0
        if (f_lockscreen == 0) { rightBound += 0x40; }
	
	//@screenlocked:
	//cmp.w	d1,d0		; has Sonic touched the	side boundary?
        //bls.s	@sides		; if yes, branch
        if (rightBound < newXint)
        {
            //@sides:
            //move.w	d0,obX(a0)
            player.X = resetX;

            //move.w	#0,obX+2(a0)
            player.ScreenY = 0;

            //move.w	#0,obVelX(a0)	; stop Sonic moving
            player.VelocityX = 0;

            //move.w	#0,obInertia(a0)
            player.Inertia = 0;
     
            //bra.s	@chkbottom
	}
     }
 
     //@chkbottom:     //move.w	(v_limitbtm2).w,d0     //addi.w	#$E0,d0
     word bottomBound = v_limitbtm2 + 224;
     //cmp.w	obY(a0),d0	; has Sonic touched the	bottom boundary?
     //blt.s	@bottom		; if yes, branch
     if (bottomBound >= player.Y)
     {	    
         /*         //rts	
         //; ===========================================================================
         //@bottom:
	 //cmpi.w	#(id_SBZ<<8)+1,(v_zone).w ; is level SBZ2 ?
         //bne.w	KillSonic	; if not, kill Sonic
         if (v_zone != ((id_SBZ<<8)+1)) { KillSonic(); }
         else
         {
             //cmpi.w	#$2000,(v_player+obX).w             //bcs.w	        KillSonic
	     if (player.X < 0x2000) { KillSonic(); }
             else
             {
	         //clr.b	(v_lastlamp).w	; clear	lamppost counter
		 v_lastlamp = 0;

                 //move.w	#1,(f_restart).w ; restart the level
		 f_restart = 1;

                 //move.w	#(id_LZ<<8)+3,(v_zone).w ; set level to SBZ3 (LZ4)
		 v_zone = (id_LZ<<8)+3;
                    
                 //rts
             }
         }    
         */
     }
//; ===========================================================================

}  //; End of function Sonic_LevelBound

//speedtopos anglepos sloperepel



void Sonic_AnglePos()
{
    
//; ---------------------------------------------------------------------------
//; Subroutine to	change Sonic's angle & position as he walks along the floor
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||

//Sonic_AnglePos:				; XREF: Obj01_MdNormal; Obj01_MdRoll
//   btst	#3,obStatus(a0)
     if ((objects[0].Status & 8) == 8)          //if sonic is on a solid object that acts as ground
     {                                          //then the code for positioning sonic on the floor is 
          //beq.s	loc_14602               //dependent on the object..
	  //moveq	#0,d0
	  //move.b	d0,($FFFFF768).w
	  (v_anglebuffer) = 0;                  //so reset angle buffer 1
	
          //move.b	d0,($FFFFF76A).w
          FFFFF76A = 0;			        //and 2
     	
	  //rts
          return;				//and quit
      }
      	
//; ===========================================================================
     
     //otherwise we initialize both angle buffers 
     //- calculate which of the 4 modes/quadrants sonic is in based on angle 
     //- run the corresponding floor angle/positioning routine for this mode..
     
     //loc_14602:
     //moveq	#3,d0
     //move.b	d0,($FFFFF768).w
     //move.b	d0,($FFFFF76A).w
     (v_anglebuffer) = 3;
     (FFFFF76A) = 3; 
     

     //move.b	obAngle(a0),d0
     //addi.b	#$20,d0
     signed char angle45 = objects[0].Angle + 0x20;   //adding 0x20,45: gives 4 equal quadrants, starting the unit circle 45deg back
		
     if (angle45 < 0)                                 //less than or equal tp 0 refers to the 2 quadrants where sonic is traversing uphill (0x60-0xDF)
     {
          //bpl.s	loc_14624
          //move.b	obAngle(a0),d0
	  signed char angle = objects[0].Angle;       //regular angle so now values less than 0 strictly upside-down
          if (angle < 0) { angle = angle - 1; }       // (aka sonic upside-down & traversing uphill) //(-0)[ 0x80:0xFF = -128:-1 ], (-1) [ 0x80:0xFF = -127:0 ]
                                                      //subtracting 1 here means to include all ranges but 45deg uphill, contrary to what happens when right-side up
          //bpl.s	loc_1461E
	  //subq.b	#1,d0
          //loc_1461E:
	  //addi.b	#$20,d0
	  angle45 = angle + 0x20;	
     }
     else
     {
          //bra.s	loc_14630
          //; ===========================================================================
          //loc_14624:
	  //move.b	obAngle(a0),d0
	  signed char angle = objects[0].Angle;
          if (angle < 0) { angle = angle + 1; }	
           
          //bpl.s	loc_1462C
	  //addq.b	#1,d0
          //loc_1462C:
	  //addi.b	#$1F,d0
          angle45 = angle + 0x1F;
     }

     //loc_14630:
     //andi.b	#$C0,d0
     byte quadrant = (byte)angle45 & 0xC0;

     if (quadrant == 0x40)
     {
          //cmpi.b	#$40,d0
	  //beq.w	Sonic_WalkVertL
	  Sonic_WalkVertL();
	  
     }
     else if (quadrant == 0x80) //-80
     {
          //cmpi.b	#$80,d0
	  //beq.w	Sonic_WalkCeiling
	  Sonic_WalkCeiling();
     }
     else if (quadrant == 0xC0) //-40
     {	
          //cmpi.b	#$C0,d0
	  //beq.w	Sonic_WalkVertR
	  Sonic_WalkVertR();
     }
     else
     {
          Sonic_Walk();
     }
}

//Sonic_Walk 

//1) calculates values for sonic sensor A and sonic sensor B { A=(X-width,Y) , B=(X+width,Y) }

//2a) passes sensor A to use as position for FINDFLOOR, which returns the height offset of the floor at that sensor (ALSO SETS CORRESPONDING ANGLE SENSOR ANGLE BUFFER)
//2b) passes sensor B to use as position for FINDFLOOR, which returns the height offset of the floor at that sensor (ALSO SETS CORRESPONDING ANGLE SENSOR ANGLE BUFFER)

//3) calls Sonic_Angle which sets sonics angle to the higher sensor's (either A or B) corresponding angle buffer
//  b) if this angle is invalid then rotate sonic back to normal...

//4) given Sonic_Angle also returns the height of the higher sensor,
//   sonic's Y POSITION is finally offset with this height


void Sonic_Walk()
{
     //move.w	obY(a0),d2
     word obY = objects[0].Y;
	
     //move.w	obX(a0),d3
     word obX = objects[0].X;

     //move.b	obHeight(a0),d0
     //ext.w	d0
     word obHeight = objects[0].Height;

     //add.w	d0,d2
     word obBottom = obY + obHeight;
     
     //move.b	obWidth(a0),d0
     //ext.w	d0
     word obWidth = objects[0].Width;

     //add.w	d0,d3
     word obRight = obX + obWidth;

     //lea	(v_anglebuffer).w,a4
     signed short *v_anglebufferPtr = &v_anglebuffer;

     //movea.w	#$10,a3
     signed short offset = 16;

     //move.w	#0,d6
     word collisionFlags = 0;

     //moveq	#$D,d5
     byte solidnessBit = 0xD;
 
     signed short rfloorDist;
     //bsr.w	FindFloor
     FindFloor(&objects[0], obBottom, obRight, solidnessBit, collisionFlags, rfloorDist, offset, v_anglebufferPtr);

     //move.w	d1,-(sp)
     //move.w	obY(a0),d2
     //move.w	obX(a0),d3
     //moveq	#0,d0
     //move.b	obHeight(a0),d0
     //ext.w	d0     //add.w	d0,d2
     //move.b	obWidth(a0),d0
     //ext.w	d0

     //neg.w	d0
     //add.w	d0,d3
     word obLeft = obX - obWidth;

     //lea	($FFFFF76A).w,a4
     signed short *v_anglebufferPtr2 = &FFFFF76A;

     //movea.w	#$10,a3     offset = 16;

     //move.w	#0,d6
     collisionFlags = 0;

     //moveq	#$D,d5
     solidnessBit = 0xD;

     signed short lfloorDist;
     //bsr.w	FindFloor
     FindFloor(&objects[0], obBottom, obLeft, solidnessBit, collisionFlags, lfloorDist, offset, v_anglebufferPtr2);
     
     //move.w	(sp)+,d0
     //bsr.w	Sonic_Angle
     signed short heightShift = Sonic_Angle(rfloorDist, lfloorDist);    //heightShift = height from ground in current 32 pixel aligned section 
                                                                        //determined by the collision maps for the 2 16x16's under sonic 
     
     //tst.w	d1							//seperately the map height values are both -subtracted from- 15, for the inverse (we are checking -under- sonic) 
     if (heightShift == 0) { return; }                                  //if there is no space under sonic then he is already touching the top of the tile 
     //beq.s	locret_146BE                                            //then there is no shift in height to account for
     if (heightShift >= 0)                                               //however if there -is- space under sonic
     {
           //bpl.s	loc_146C0
	   //loc_146C0:
	   //cmpi.w	#$E,d1
	   if (heightShift > 14)                                        //
           {
                //bgt.s	loc_146CC
                //loc_146CC:
	        
                //tst.b	$38(a0)
	        //bne.s	loc_146C6
                if (player.Variables[16] != 0)
                {
                     //loc_146C6:
	             //add.w	d1,obY(a0)
                     objects[0].Y=objects[0].Y + heightShift;
                     
                     //rts
                }
                else                                                 
                {
                     //bset	#1,obStatus(a0)
                     objects[0].Status = objects[0].Status | 2;       //set bit 1, sonic in the air
	         
	             //bclr	#5,obStatus(a0)
	             player.Status=player.Status-(player.Status&32);  //clear bit 5 (sonic not pushing anything)

                     //move.b	#1,obNextAni(a0)
		     objects[0].NextAni = 1;			      //next jump frame
                }
                //rts
         }
         else
         {
             objects[0].Y=objects[0].Y + heightShift;
         }
	 //locret_146E6:
	 //rts	
     }
     else
     { 
           //cmpi.w	#-$E,d1
           if (heightShift >= -14)
           {
               //blt.s	locret_146E6   
	       objects[0].Y = objects[0].Y + heightShift;
	
	      //add.w	d1,obY(a0)
              //locret_146BE:
	      //rts
           }
     }	
     //; ===========================================================================

	
} //; End of function Sonic_AnglePos

//; ---------------------------------------------------------------------------
//; Subroutine allowing Sonic to walk up a vertical slope/wall to	his right
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


//Sonic_WalkVertR:			; XREF: Sonic_AnglePos

void Sonic_WalkVertR()
{
     //move.w	obY(a0),d2
     word obY = objects[0].Y;
	
     //move.w	obX(a0),d3
     word obX = objects[0].X;

     //moveq	#0,d0
     //move.b	obWidth(a0),d0
     //ext.w	d0
     word obWidth = objects[0].Width;

     //neg.w	d0
     //add.w	d0,d2
     word obTop = obY - obWidth;
     
     //move.b	obHeight(a0),d0
     //ext.w	d0
     word obHeight = objects[0].Height;

     //add.w	d0,d3
     word obRight = obX + obHeight;

     //lea	($FFFFF768).w,a4
     signed short *v_anglebufferPtr = &v_anglebuffer; 

     //movea.w	#$10,a3
     signed short offset = 16;

     //move.w	#0,d6
     word collisionFlags = 0;

     //moveq	#$D,d5
     byte solidnessBit = 0xD;
 
     signed short lwallDist;
     //bsr.w	FindWall
     FindWall(&objects[0], obTop, obRight, solidnessBit, collisionFlags, lwallDist, offset, v_anglebufferPtr);

     //move.w	d1,-(sp)
     //move.w	obY(a0),d2
     //move.w	obX(a0),d3
     //moveq	#0,d0
     //move.b	obWidth(a0),d0     //ext.w	d0
     //add.w	d0,d2
     word obBottom = obY + obWidth;
     //move.b	obHeight(a0),d0
     //ext.w	d0
     //add.w	d0,d3

     signed short *v_anglebufferPtr2 = &FFFFF76A; 

     //movea.w	#$10,a3
     offset = 16;

     //move.w	#0,d6
     collisionFlags = 0;

     //moveq	#$D,d5
     solidnessBit = 0xD;

     signed short rwallDist;
     FindWall(&objects[0], obBottom, obRight, solidnessBit, collisionFlags, rwallDist, offset, v_anglebufferPtr2);
     //bsr.w	FindWall
     //move.w	(sp)+,d0
		
     //bsr.w	Sonic_Angle
     signed short heightShift = Sonic_Angle(lwallDist, rwallDist);
     
     //tst.w	d1
     if (heightShift == 0) { return; }

     if (heightShift > 0)
     {
	   if (heightShift > 14)
           {
                if (player.Variables[16] != 0)
                {
                     objects[0].X=objects[0].X + heightShift;
                }
                else
                {
                     //bset	#1,obStatus(a0)
                     objects[0].Status = objects[0].Status | 2;   //set bit 1, sonic in the air due to a jump
	         
	             //bclr	#5,obStatus(a0)
	             player.Status=player.Status-(player.Status&32);  //clear bit 5 (sonic not pushing anything)

                     //move.b	#1,obNextAni(a0)
		     objects[0].NextAni = 1;			      //next jump frame
                }
                //rts
         }
         else
         {
             objects[0].X = objects[0].X + heightShift;
         }
	 //locret_146E6:
	 //rts	
     }
     else
     { 
           //cmpi.w	#-$E,d1
           if (heightShift >= -14)
           { 
	       objects[0].X = objects[0].X + heightShift;
           }
     }	
} //; End of function Sonic_WalkVertR

/*; ===========================================================================
	move.l	obX(a0),d2
	move.w	obVelX(a0),d0
	ext.l	d0
	asl.l	#8,d0
	sub.l	d0,d2
	move.l	d2,obX(a0)
	move.w	#$38,d0
	ext.l	d0
	asl.l	#8,d0
	sub.l	d0,d3
	move.l	d3,obY(a0)
	rts	
	; ===========================================================================

	locret_1470A:
	rts	
	; ===========================================================================
	move.l	obY(a0),d3
	move.w	obVelY(a0),d0
	subi.w	#$38,d0
	move.w	d0,obVelY(a0)
	ext.l	d0
	asl.l	#8,d0
	sub.l	d0,d3
	move.l	d3,obY(a0)
	rts	
	rts	
	; ===========================================================================
	move.l	obX(a0),d2
	move.l	obY(a0),d3
	move.w	obVelX(a0),d0
	ext.l	d0
	asl.l	#8,d0
	sub.l	d0,d2
	move.w	obVelY(a0),d0
	ext.l	d0
	asl.l	#8,d0
	sub.l	d0,d3
	move.l	d2,obX(a0)
	move.l	d3,obY(a0)
	rts	
}*/



//; ---------------------------------------------------------------------------
//; Subroutine to	change Sonic's angle as he walks along the floor
//; ---------------------------------------------------------------------------
//sets sonics angle to either of the angle buffers depending on which sensor picks the highest height
//if either of the values in the right angle buffer is invalid then rotate sonic back to normal...

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


//Sonic_Angle:				; XREF: Sonic_AnglePos; et al
signed short Sonic_Angle(signed short sensorA, signed short sensorB)         
{
     
     //move.b	($FFFFF76A).w,d2
     signed char angle = (signed char)(FFFFF76A);
     signed short highSensor=sensorB;     

     //cmp.w	d0,d1
     //ble.s	loc_1475E
     if (sensorB > sensorA)
     {
         //move.b	($FFFFF768).w,d2
         angle = (signed char)(v_anglebuffer);

         //move.w	d0,d1
         highSensor = sensorA;
     }
             
     //loc_1475E:
     //btst	#0,d2
     signed char testAngle = angle;
     if ((testAngle & 1) != 0)
     {
          //bne.s	loc_1476A
          //loc_1476A:
	  //move.b	obAngle(a0),d2
          byte obAngle = objects[0].Angle;
	  
          //addi.b	#$20,d2
	  //andi.b	#$C0,d2
	  angle = (obAngle + 0x20) & 0xC0;
                          //move.b	d2,obAngle(a0)
	  objects[0].Angle = angle;	
     }
     else
     {
	  //move.b	d2,obAngle(a0)
	  objects[0].Angle = angle;
     }
     return highSensor;
//rts	
//; ===========================================================================
} //; End of function Sonic_Angle


void Sonic_WalkCeiling()
{
     
//; ---------------------------------------------------------------------------
//; Subroutine allowing Sonic to walk upside-down
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||

     //move.w	obY(a0),d2
     word obY = objects[0].Y;
	
     //move.w	obX(a0),d3
     word obX = objects[0].X;

     //move.b	obHeight(a0),d0
     //ext.w	d0
     word obHeight = objects[0].Height;

     //sub.w	d0,d2
     //eori.w	#$F,d2
     word obTop = (obY - obHeight) ^ 0xF;
     
     //move.b	obWidth(a0),d0
     //ext.w	d0
     word obWidth = objects[0].Width;

     //add.w	d0,d3
     word obRight = obX + obWidth;

     //lea	(v_anglebuffer).w,a4
     signed short *v_anglebufferPtr = &v_anglebuffer;

     //movea.w	#-$10,a3
     signed short offset = -16;

     //move.w	#$1000,d6
     word collisionFlags = 0x1000;

     //moveq	#$D,d5
     byte solidnessBit = 0xD;
 
     signed short rceilDist;
     //bsr.w	FindFloor
     FindFloor(&objects[0], obTop, obRight, solidnessBit, collisionFlags, rceilDist, offset, v_anglebufferPtr);

     //move.w	d1,-(sp)
     //move.w	obY(a0),d2
     //move.w	obX(a0),d3
     //moveq	#0,d0
     //move.b	obHeight(a0),d0
     //ext.w	d0     //add.w	d0,d2
     //move.b	obWidth(a0),d0
     //ext.w	d0

     //neg.w	d0
     //add.w	d0,d3
     word obLeft = obX - obWidth;

     //lea	($FFFFF76A).w,a4
     signed short *v_anglebufferPtr2 = &FFFFF76A;

     //movea.w	#-$10,a3     offset = -16;

     //move.w	#$1000,d6
     collisionFlags = 0x1000;

     //moveq	#$D,d5
     solidnessBit = 0xD;

     signed short lceilDist;
     //bsr.w	FindFloor
     FindFloor(&objects[0], obTop, obLeft, solidnessBit, collisionFlags, lceilDist, offset, v_anglebufferPtr2);
     
     //move.w	(sp)+,d0
     //bsr.w	Sonic_Angle
     signed short heightShift = Sonic_Angle(rceilDist, lceilDist);

     //tst.w	d1
     if (heightShift == 0) { return; }

     if (heightShift > 0)
     {

	   if (heightShift > 14)
           {

                if (player.Variables[16] != 0)
                {
                     objects[0].Y=objects[0].Y - heightShift;
                     
                     //rts
                }
                else
                {
                     //bset	#1,obStatus(a0)
                     objects[0].Status = objects[0].Status | 2;   //set bit 1, sonic in the air due to a jump
	         
	             //bclr	#5,obStatus(a0)
	             player.Status=player.Status-(player.Status&32);  //clear bit 5 (sonic not pushing anything)

                     //move.b	#1,obNextAni(a0)
		     objects[0].NextAni = 1;			      //next jump frame
                }
                //rts
         }
         else
         {
             objects[0].Y = objects[0].Y - heightShift;
         }
	 //locret_146E6:
	 //rts	
     }
     else
     { 
           //cmpi.w	#-$E,d1
           if (heightShift >= -14)
           {
               //blt.s	locret_146E6   
	       objects[0].Y = objects[0].Y - heightShift;
	
	      //add.w	d1,obY(a0)
              //locret_146BE:
	      //rts
           }
     }	
     //; ===========================================================================

}

void Sonic_WalkVertL()
{
     //move.w	obY(a0),d2
     word obY = objects[0].Y;
	
     //move.w	obX(a0),d3
     word obX = objects[0].X;

     //moveq	#0,d0
     //move.b	obWidth(a0),d0
     word obWidth = objects[0].Width;

     //ext.w	d0
     //sub.w	d0,d2
     word obTop = obY - obWidth;
     
     //move.b	obHeight(a0),d0
     //ext.w	d0
     word obHeight = objects[0].Height;

     //sub.w	d0,d3
     //eori.w	#$F,d3
     word obLeft = (obX - obHeight) ^ 0xF;

     //lea	($FFFFF768).w,a4
     signed short *v_anglebufferPtr = &v_anglebuffer; 

     //movea.w	#-$10,a3
     signed short offset = -16;

     //move.w	#$800,d6
     word collisionFlags = 0x800;

     //moveq	#$D,d5
     byte solidnessBit = 0xD;
 
     signed short lwallDistL;
     //bsr.w	FindWall
     FindWall(&objects[0], obTop, obLeft, solidnessBit, collisionFlags, lwallDistL, offset, v_anglebufferPtr);

     //move.w	d1,-(sp)
     //move.w	obY(a0),d2
     //move.w	obX(a0),d3
     //moveq	#0,d0
     //move.b	obWidth(a0),d0     //ext.w	d0
     //add.w	d0,d2
     word obBottom = obY + obWidth;
     //move.b	obHeight(a0),d0
     //ext.w	d0
     //add.w	d0,d3

     signed short *v_anglebufferPtr2 = &FFFFF76A; 

     //movea.w	#-$10,a3
     offset = -16;

     //move.w	#$800,d6
     collisionFlags = 0;

     //moveq	#$D,d5
     solidnessBit = 0xD;

     signed short lwallDistR;
     FindWall(&objects[0], obBottom, obLeft, solidnessBit, collisionFlags, lwallDistR, offset, v_anglebufferPtr2);
     //bsr.w	FindWall
     //move.w	(sp)+,d0
		
     //bsr.w	Sonic_Angle
     signed short heightShift = Sonic_Angle(lwallDistL, lwallDistR);
     
     //tst.w	d1
     if (heightShift == 0) { return; }

     if (heightShift > 0)
     {
	   if (heightShift > 14)
           {
                if (player.Variables[16] != 0)
                {
                     objects[0].X=objects[0].X - heightShift;
                }
                else
                {
                     //bset	#1,obStatus(a0)
                     objects[0].Status = objects[0].Status | 2;   //set bit 1, sonic in the air due to a jump
	         
	             //bclr	#5,obStatus(a0)
	             player.Status=player.Status-(player.Status&32);  //clear bit 5 (sonic not pushing anything)

                     //move.b	#1,obNextAni(a0)
		     objects[0].NextAni = 1;			      //next jump frame
                }
                //rts
         }
         else
         {
             objects[0].X = objects[0].X - heightShift;
         }
	 //locret_146E6:
	 //rts	
     }
     else
     { 
           //cmpi.w	#-$E,d1
           if (heightShift >= -14)
           { 
	       objects[0].X = objects[0].X - heightShift;
           }
     }	
}

void Sonic_SlopeRepel()
{

//; ---------------------------------------------------------------------------
//; Subroutine to	push Sonic down	a slope
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


    //Sonic_SlopeRepel:			; XREF: Obj01_MdNormal; Obj01_MdRoll    //nop
    asm volatile("nop");
    
    //tst.b	$38(a0)
    //bne.s	locret_13580
    if (player.Variables[16] == 0)
    {
        //tst.w	$3E(a0)
	//bne.s	loc_13582
        if (getobjvariableword(0x3E,objects[0]) == 0)   //control lock timer, if done counting down
        {
	    //move.b	obAngle(a0),d0
            byte angle = player.Angle;

	    //addi.b	#$20,d0
	    //andi.b	#$C0,d0
            byte quadrant = ((angle + 0x20) & 0xC0);

	    //beq.s	locret_13580
            if (quadrant != 0)
            {
                //move.w	obInertia(a0),d0
		signed short absInertia = player.Inertia;
 
                //bpl.s	loc_1356A
		//neg.w	d0
                if (absInertia<0) { absInertia = -absInertia; }

                //loc_1356A:
		//cmpi.w	#$280,d0
		//bcc.s	locret_13580
                if (absInertia < 0x280)
                {
		    //clr.w	obInertia(a0)
		    player.Inertia = 0;
                
                    //bset	#1,obStatus(a0)
                    player.Status = player.Status | 2;

		    //move.w	#$1E,$3E(a0)
                    setobjvariableword(0x3E,objects[0],0x1E);   //lock controls for 0x1E calls to sloperepel
		}
            }
        }
        else
        {
             //loc_13582:
	     //subq.w	#1,$3E(a0)
	     subobjvariableword(0x3E,objects[0],1);
        }
        //rts
        //locret_13580:
	//rts		
    }
    //; ===========================================================================


} //; End of function Sonic_SlopeRepel

void Sonic_JumpHeight()
{
     
     //; ---------------------------------------------------------------------------
     //; Subroutine controlling Sonic's jump height/duration
     //; ---------------------------------------------------------------------------

     //; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


     //Sonic_JumpHeight:			; XREF: Obj01_MdJump; Obj01_MdJump2
     //tst.b	$3C(a0)
     //beq.s	loc_134C4
     if (player.Variables[20] != 0)
     { 
          //move.w	#-$400,d1
          signed short jumpVelocity = -0x400;

	  //btst	#6,obStatus(a0)
	  //beq.s loc_134AE
          //move.w	#-$200,d1
          if ((player.Status & (1<<6))==(1<<6))
               jumpVelocity = -0x200;

          //loc_134AE:
	  //cmp.w	obVelY(a0),d1
          //ble.s	locret_134C2
          if (jumpVelocity > player.VelocityY)
	  {
	       //move.b	(v_jpadhold2).w,d0
               byte holdState = v_jpadhold2;
           
               //andi.b	#btnABC,d0	; is A, B or C pressed?
               //bne.s	locret_134C2	; if yes, branch
               if ((holdState & btnABC) == 0)    
	            //move.w	d1,obVelY(a0)
                    player.VelocityY = jumpVelocity;          //should not be 'held' for a jump, buttons pressed
           }
      }
      //locret_134C2:
      //rts
      // ; ===========================================================================
      else
      {
           //loc_134C4:
	   //cmpi.w	#-$FC0,obVelY(a0)
           //bge.s	locret_134D2
	   if (player.VelocityY < -0xFC0)	
                //move.w	#-$FC0,obVelY(a0)
                player.VelocityY = -0xFC0;
      }

      //locret_134D2:
      //rts	
} //; End of function Sonic_JumpHeight

void Sonic_JumpDirection()
{

//; ---------------------------------------------------------------------------
//; Subroutine to	change Sonic's direction while jumping
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


     //Sonic_JumpDirection:			; XREF: Obj01_MdJump; Obj01_MdJump2
     //move.w	(v_sonspeedmax).w,d6
     word sonspeedmax = v_sonspeedmax;

     //move.w	(v_sonspeedacc).w,d5
     //asl.w	#1,d5
     word jumpspeedacc = v_sonspeedacc * 2;
     //btst	#4,obStatus(a0)
     //bne.s	Obj01_ResetScr2
     if ((player.Status & (1<<4)) != (1<<4))     //rolling after jumping
     {
          
          //move.w	obVelX(a0),d0
          signed short newVelocityX = player.VelocityX;

	  //btst	#bitL,(v_jpadhold2).w ; is left being pressed?
          //beq.s	loc_13278	; if not, branch
	  if ((v_jpadhold2 & (1<<bitL))==(1<<bitL))
          {
               //bset	#0,obStatus(a0)
               player.Status = player.Status | 1;
	       
               //sub.w	d5,d0
	       newVelocityX = newVelocityX - jumpspeedacc;

               //move.w	d6,d1
               //neg.w	d1
               signed short negspeedmax = -sonspeedmax;

	       //cmp.w	d1,d0
               if (newVelocityX <= negspeedmax)
	            //bgt.s	loc_13278
	            //move.w	d1,d0
                    newVelocityX = negspeedmax;
          }

          //loc_13278:
          //btst	#bitR,(v_jpadhold2).w ; is right being pressed?
	  //beq.s	Obj01_JumpMove	; if not, branch
          if ((v_jpadhold2 & (1<<bitR))==(1<<bitR))
	  {
	       //bclr	#0,obStatus(a0)
               player.Status = player.Status - (player.Status&1);

	       //add.w	d5,d0
	       newVelocityX = newVelocityX + jumpspeedacc;
 
               //cmp.w	d6,d0
               if (newVelocityX >= sonspeedmax)
	            //blt.s	Obj01_JumpMove
		    //move.w	d6,d0
                    newVelocityX = sonspeedmax;
          }

          //Obj01_JumpMove:
	  //move.w	d0,obVelX(a0)	; change Sonic's horizontal speed
          player.VelocityX = newVelocityX;
    }
    //Obj01_ResetScr2:
    //cmpi.w	#$60,(v_lookshift).w ; is screen in its default position?
    if (v_lookshift!=0x60)
    {
         //beq.s	loc_132A4	; if yes, branch   
    	 //bcc.s	loc_132A0
    	 if (v_lookshift>0x60)
         {
              //loc_132A0:
    	      //subq.w	#2,(v_lookshift).w ; move screen back to default
              v_lookshift=v_lookshift-2;
         }
         else
         {
              //addq.w	#4,(v_lookshift).w ; move screen back to default
              v_lookshift=v_lookshift+4;
         }
    }

    //loc_132A4:
    //cmpi.w	#-$400,obVelY(a0) ; is Sonic moving faster than -$400 upwards?
    //bcs.s	locret_132D2	; if yes, branch
    if (player.VelocityY > -0x400)
    {
         //move.w	obVelX(a0),d0
         signed short obVelX = player.VelocityX;

	 //move.w	d0,d1
         //asr.w	#5,d1
         signed short scaleVelX = (obVelX / 32);

	 //beq.s	locret_132D2
         if (scaleVelX != 0)
         {
	      //bmi.s	loc_132C6
	      if (scaleVelX < 0)
              {
                   //; ===========================================================================
                   //loc_132C6:
		   //sub.w	d1,d0
                   signed short newVelocityX = obVelX - scaleVelX;

		   //bcs.s	loc_132CE
		   if (newVelocityX > 0) 
                        //move.w	#0,d0
                        newVelocityX = 0;
                  
                   //loc_132CE:
		   //move.w	d0,obVelX(a0)
                   player.VelocityX = newVelocityX;
                   
                   //locret_132D2:
		   //rts
              }
              else
              {	
                   //sub.w	d1,d0
		   signed short newVelocityX = obVelX - scaleVelX;
                   
                   //bcc.s	loc_132C0
		   if (newVelocityX < 0)
                        //move.w	#0,d0
                        newVelocityX = 0;
                   
                   //loc_132C0:
		   //move.w	d0,obVelX(a0)
	           player.VelocityX = newVelocityX;

              }    //rts	
         }
    }
} //; End of function Sonic_JumpDirection

void Sonic_JumpAngle()
{

//; ---------------------------------------------------------------------------
//; Subroutine to	return Sonic's angle to 0 as he jumps
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


     #define newAngle angle
     //Sonic_JumpAngle:			; XREF: Obj01_MdJump; Obj01_MdJump2
     //move.b	obAngle(a0),d0	; get Sonic's angle
     signed char angle = player.Angle;
		
     //beq.s	locret_135A2	; if already 0,	branch
     if (angle != 0)
     {
          //bpl.s	loc_13598	; if higher than 0, branch
          if (angle < 0)
          {
               //addq.b	#2,d0		; increase angle
               newAngle = angle + 2;

               //bcc.s	loc_13596
	       if (newAngle > 0)
	            //moveq	#0,d0
                    newAngle = 0;
          }
          else
          {
               //loc_13598:
	       //subq.b	#2,d0		; decrease angle
	       newAngle = angle - 2;

               //bcc.s	loc_1359E
	       if (newAngle > 0)
	            //moveq	#0,d0
                    newAngle = 0;
          }
          //loc_13596:
	  //bra.s	loc_1359E
          
          //; ===========================================================================

          //loc_1359E:
          //move.b	d0,obAngle(a0)
          player.Angle = newAngle;
     }
     //locret_135A2:
     //rts	

} //; End of function Sonic_JumpAngle

void Sonic_Floor()
{

//Any time Sonic is in the air, he doesn't have to worry about angles, Gsp, slp, or any of that jazz. 
//All he has to do is move using Xsp and Ysp until he detects the ground, at which point he re-enters the ground state.

//(Technically, we -are- dealing with angles here, but only one-of which is derived from Xsp/VelocityX and Ysp/VelocityY)

//; ---------------------------------------------------------------------------
//; Subroutine for Sonic to interact with	the floor after	jumping/falling
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


    //Sonic_Floor:				; XREF: Obj01_MdJump; Obj01_MdJump2
    //move.w	obVelX(a0),d1
    signed short obVelX = player.VelocityX;
 
    //move.w	obVelY(a0),d2
    signed short obVelY = player.VelocityY;

    signed char fallAngle;
    //jsr	(CalcAngle).l
    fallAngle = CalcAngle(obVelX, obVelY);

    //move.b	d0,($FFFFFFEC).w
    FFFFFFEC = fallAngle;

    //subi.b	#$20,d0
    byte angle45 = fallAngle - 0x20;

    //move.b	d0,($FFFFFFED).w
    FFFFFFED = angle45;

    //andi.b	#$C0,d0
    byte quadrant = angle45 & 0xC0;

    //move.b	d0,($FFFFFFEE).w
    FFFFFFEE = quadrant;

    byte angle;
    signed short wallDist, ceilDist;

    //cmpi.b	#$40,d0
    if (quadrant == 0x40)
    {
        //beq.w	loc_13680
        //loc_13680:
	//bsr.w	Sonic_HitWall
        Sonic_HitWallLeft(wallDist, angle);

	//tst.w	d1
        //bpl.s	loc_1369A
        if (wallDist < 0)
        {
            //sub.w	d1,obX(a0)
            player.X = player.X - wallDist;

	    //move.w	#0,obVelX(a0)
            player.VelocityX = 0;
            //move.w	obVelY(a0),obInertia(a0)
            player.VelocityY = player.Inertia;

	}   //rts
        else
        {
            
            //; ===========================================================================
            //loc_1369A:
	    //bsr.w	Sonic_DontRunOnWalls            Sonic_CheckCeiling(ceilDist, angle);

	    //tst.w	d1
            //bpl.s	loc_136B4
            if (ceilDist < 0)
            {
                //sub.w	d1,obY(a0)
		player.Y = player.Y - ceilDist;

                //tst.w	obVelY(a0)
                //bpl.s	locret_136B2
                if (player.VelocityY < 0)
		    //move.w	#0,obVelY(a0)                    player.VelocityY = 0;
            }
            //locret_136B2:
	    //rts	
            //; ===========================================================================
            else
            {
                //loc_136B4:
		//tst.w	obVelY(a0)
		//bmi.s	locret_136E0
		if (player.VelocityY >= 0)
                {
                    #define floorDist highSensor
                    signed short lowSensor, highSensor;
                    byte airAngle;
                    
                    //bsr.w	Sonic_HitFloor
		    Sonic_HitFloor(lowSensor, highSensor, airAngle);

                    //tst.w	d1
                    //bpl.s	locret_136E0
		    if (floorDist <= 0)
                    {
		        //add.w	d1,obY(a0)
                        player.Y = player.Y + floorDist;

		        //move.b	d3,obAngle(a0)
                        player.Angle = airAngle;

		        //bsr.w	Sonic_ResetOnFloor
                        Sonic_ResetOnFloor();

		        //move.b	#id_Walk,obAnim(a0)
                        player.Anim = id_Walk;

		        //move.w	#0,obVelY(a0)
                        player.VelocityY = 0;

		        //move.w	obVelX(a0),obInertia(a0)
                        player.Inertia = player.VelocityX;
                    }
                }
            }
        }
        //locret_136E0:
	//rts	
    }
    //cmpi.b	#$80,d0
    else if (quadrant == 0x80)
    {
        //beq.w	loc_136E2
        //loc_136E2:
        //bsr.w	Sonic_HitWall
        Sonic_HitWallLeft(wallDist, angle);
         
	//tst.w	d1
        //bpl.s	loc_136F4
        if (wallDist < 0)
        {
	    //sub.w	d1,obX(a0)
            player.X = player.X - wallDist;   //make sonic stick to walls

	    //move.w	#0,obVelX(a0)
            player.VelocityX = 0;
        }
         
        //bsr.w	sub_14EB4
        Sonic_HitWallRight(wallDist, angle);

	//tst.w	d1
	//bpl.s	loc_13706
        if (wallDist < 0)
        {
	    //add.w	d1,obX(a0)
            player.X = player.X + wallDist;
        
	    //move.w	#0,obVelX(a0)
            player.VelocityX = 0;
        }

        //loc_13706
	//bsr.w	Sonic_DontRunOnWalls        Sonic_CheckCeiling(ceilDist, angle);

	//tst.w	d1
        //bpl.s	locret_1373C
        if (ceilDist < 0)
        {
            //sub.w	d1,obY(a0)
            player.Y = player.Y - ceilDist;

            //move.b	d3,d0
            byte floorAngle = angle;

	    //addi.b	#$20,d0
	    //andi.b	#$40,d0
            //bne.s	loc_13726
            if (floorAngle == 0)
                //move.w	#0,obVelY(a0)
                player.VelocityY = 0;
            else
            {
                //move.b	d3,obAngle(a0)
		player.Angle = floorAngle;
                
                //bsr.w	Sonic_ResetOnFloor
		Sonic_ResetOnFloor();

                //move.w	obVelY(a0),obInertia(a0)
		player.Inertia = player.VelocityY;

                //tst.b	d3
		//bpl.s	locret_1373C
                if (floorAngle >= 0x80)
		    //neg.w	obInertia(a0)
                    player.Inertia = -player.Inertia;
            }
        }
        //rts	
        //; ===========================================================================
        //loc_13726:        //locret_1373C:
	//rts	      
    }
    //cmpi.b	#$C0,d0
    else if (quadrant == 0xC0)
    {
        //beq.w	loc_1373E
        //loc_1373E:
	//bsr.w	sub_14EB4
        Sonic_HitWallRight(wallDist, angle);

	//tst.w	d1
	//bpl.s	loc_13758
        if (wallDist <= 0)
        {
	    //add.w	d1,obX(a0)
            player.X = player.X + wallDist;
        
	    //move.w	#0,obVelX(a0)
            player.VelocityX = 0;

            //move.w	obVelY(a0),obInertia(a0)
            player.Inertia = player.VelocityY;
        }
        else
        {
            //bsr.w	Sonic_DontRunOnWalls
            Sonic_CheckCeiling(ceilDist, angle);

	    //tst.w	d1
            //bpl.s	loc_13772
            if (ceilDist < 0)
            {
                //sub.w	d1,obY(a0)
		player.Y = player.Y - ceilDist;

                //tst.w	obVelY(a0)
                //bpl.s	locret_13770
                if (player.VelocityY <= 0)
		    //move.w	#0,obVelY(a0)                    player.VelocityY = 0;
            }            else
            {
                 //loc_136B4:
		//tst.w	obVelY(a0)
		//bmi.s	locret_1379E
		if (player.VelocityY >= 0)
                {
                    #define floorDist highSensor
                    signed short lowSensor, highSensor;
                    byte airAngle;
                    
                    //bsr.w	Sonic_HitFloor
		    Sonic_HitFloor(lowSensor, highSensor, airAngle);

                    //tst.w	d1
                    //bpl.s	locret_1379E
		    if (floorDist <= 0)
                    {
		        //add.w	d1,obY(a0)
                        player.Y = player.Y + floorDist;

		        //move.b	d3,obAngle(a0)
                        player.Angle = airAngle;

		        //bsr.w	Sonic_ResetOnFloor
                        Sonic_ResetOnFloor();

		        //move.b	#id_Walk,obAnim(a0)
                        player.Anim = id_Walk;

		        //move.w	#0,obVelY(a0)
                        player.VelocityY = 0;

		        //move.w	obVelX(a0),obInertia(a0)
                        player.Inertia = player.VelocityX;
                    }
                }
            }
        }
        //locret_1379E:
	//rts	
    }
    else
    {
        //Sonic has to be able to bump into walls, just like when he's on the ground. 
        //So there's a horizontal sensor line, originating at his Y position, and stretching from X-10 to X+10.


        //bsr.w	Sonic_HitWall
        Sonic_HitWallLeft(wallDist, angle);
         
	//tst.w	d1
        //bpl.s	loc_135F0
        //So when Sonic detects a collision with his horizontal sensor line, 
        //his Xsp is only set to 0 if hes moving in the direction of the wall, not away from it.
        //(If it were otherwise, he'd stick to walls as he fell past them.)
        if (wallDist < 0)
        {
	    //sub.w	d1,obX(a0)
            player.X = player.X - wallDist;   //make sonic stick to walls

	    //move.w	#0,obVelX(a0)
            player.VelocityX = 0;
        }

        //loc_135F0:
	//bsr.w	sub_14EB4
        Sonic_HitWallRight(wallDist, angle);

	//tst.w	d1
	//bpl.s	loc_13602
        //.... same applies for the right sensor
        if (wallDist < 0)
        {
	    //add.w	d1,obX(a0)
            player.X = player.X + wallDist;
        
	    //move.w	#0,obVelX(a0)
            player.VelocityX = 0;
        }

        #define floorDist highSensor
        signed short lowSensor, highSensor;
        byte airAngle;

        //loc_13602:
	//bsr.w	Sonic_HitFloor
        //Sonic's A and B sensors are much the same in the air as they are on the ground...
        Sonic_HitFloor(lowSensor, highSensor, airAngle);

	//move.b	d1,($FFFFFFEF).w
        FFFFFFEF = floorDist;

	//tst.w	d1
        //bpl.s	locret_1367E
        //The difference is, when they detect a solid tile, Sonic isn't immediately set to the height found in the tile minus 20...
        if (floorDist < 0)
        {
	    //move.b	obVelY(a0),d2
            //addq.b	#8,d2
	    //neg.b	d2
            signed char distYPot = -(player.VelocityYdist + 8);  //sonic's potential distance coverage in the Y direction based on current Y velocity

            //Instead, he's only set to it if he's already lower than that height. Otherwise he'd suck to the floor when he got close to it.
	    //cmp.b	d2,d1
            //bge.s	loc_1361E
            //cmp.b	d2,d0
	    //blt.s	locret_1367E
            if ((highSensor >= distYPot) || (lowSensor >= distYPot))
            {
                //loc_1361E:
		//add.w	d1,obY(a0)
                player.Y = player.Y + floorDist;

		//move.b	d3,obAngle(a0)
		player.Angle = airAngle;

                //bsr.w	Sonic_ResetOnFloor
		Sonic_ResetOnFloor();

                //--Reacquisition Of The Ground--
                //move.b	#id_Walk,obAnim(a0)
		player.Anim = id_Walk;

                //move.b	d3,d0
                byte floorAngle = airAngle;

		//addi.b	#$20,d0
		//andi.b	#$40,d0
		byte floorAngle45 = (floorAngle + 0x20) & 0x40;

                //bne.s	loc_1365C
                ////When the floor angle detected is in the range of $F0~$FF (and their mirror images, $00~$0F), 
                if (floorAngle45 == 0)
                {
		    //move.b	d3,d0
		    //addi.b	#$10,d0
		    //andi.b	#$20,d0
                    byte floorAngle225 = (floorAngle + 0x10) & 0x20;
   
		    //beq.s	loc_1364E
                                      
                    if (floorAngle225 == 0)
                    {
                        //loc_1364E:
		        //move.w	#0,obVelY(a0)
                        player.VelocityY = 0;

		        //move.w	obVelX(a0),obInertia(a0)
                        //Gsp is set to the value of Xsp
		        player.Inertia = player.VelocityX;

                        //rts
                        return;	
                    }
                    else
                    {
                        
                        //asr	obVelY(a0)
                        player.VelocityY = player.VelocityY/2; //player.VelocityYdist??
		
                        //bra.s	loc_13670
                    }
                }
                else
                {
                    //loc_1365C:
		    //move.w	#0,obVelX(a0)
		    player.VelocityX = 0;
                  
                    //cmpi.w	#$FC0,obVelY(a0)
                    //ble.s	loc_13670
		    if (player.VelocityY > 0xFC0)
                        //move.w	#$FC0,obVelY(a0)
                        player.VelocityY = 0xFC0;
                }
            
                //loc_13670:
	        //move.w	obVelY(a0),obInertia(a0)
		player.Inertia = player.VelocityY;
 
                //tst.b	d3
		//bpl.s	locret_1367E
                if (floorAngle >= 0x80)
		    //neg.w	obInertia(a0)
                    player.Inertia = -player.Inertia;  
            }
        }
    }
    //locret_1367E:
    //rts	
} //; End of function Sonic_Floor

void Sonic_ResetOnFloor()
{
    //Sonic_ResetOnFloor:			; XREF: PlatformObject; et al
    

    //loc_137AE:	
    //btst	#4,obStatus(a0)
    //beq.s	loc_137AE
    if ((player.Status & 16)==16)
    {
        //nop
        asm volatile("nop");
        //nop
        asm volatile("nop");
        //nop
        asm volatile("nop");
    }

    //bclr #5,obStatus(a0)
    player.Status = player.Status - (player.Status & 32);

    //bclr	#1,obStatus(a0)
    player.Status = player.Status - (player.Status & 2);

    //bclr	#4,obStatus(a0)
    player.Status = player.Status - (player.Status & 16);

    //btst	#2,obStatus(a0)
    if ((player.Status&4)==4)
    {
        //beq.s	loc_137E4
        //bclr	#2,obStatus(a0)
        player.Status = player.Status - (player.Status & 4);

	//move.b	#$13,obHeight(a0)
        player.Height = 19;

	//move.b	#9,obWidth(a0)
        player.Width = 9;
 
	//move.b	#id_Walk,obAnim(a0) ; use running/walking animation
        player.Anim = id_Walk;

	//subq.w	#5,obY(a0)
        player.Y = player.Y - 5;
    }
    //loc_137E4:
    //move.b	#0,$3C(a0)
    player.Variables[20] = 0;

    //move.w	#0,(v_itembonus).w
    v_itembonus = 0;
}
    
     
void Sonic_HitFloor(signed short &lowSensor, signed short &highSensor, byte &angle)
{
     //move.w	obY(a0),d2
     word obY = objects[0].Y;
	
     //move.w	obX(a0),d3
     word obX = objects[0].X;

     //moveq	#0,d0
     //move.b	obHeight(a0),d0
     //ext.w	d0
     word obHeight = objects[0].Height;

     //add.w	d0,d2
     word obBottom = obY + obHeight;
     
     //move.b	obWidth(a0),d0
     //ext.w	d0
     word obWidth = objects[0].Width;

     //add.w	d0,d3
     word obRight = obX + obWidth;

     //lea	(v_anglebuffer).w,a4
     signed short *v_anglebufferPtr = &v_anglebuffer;

     //movea.w	#$10,a3
     signed short offset = 16;

     //move.w	#0,d6
     word collisionFlags = 0;

     //moveq	#$D,d5
     byte solidnessBit = 0xD;
 
     signed short rfloorDist;
     //bsr.w	FindFloor
     FindFloor(&objects[0], obBottom, obRight, solidnessBit, collisionFlags, rfloorDist, offset, v_anglebufferPtr);

     //move.w	d1,-(sp)
     
     //move.w	obY(a0),d2
     //move.w	obX(a0),d3
     //moveq	#0,d0
     //move.b	obHeight(a0),d0
     //ext.w	d0     //add.w	d0,d2
     //move.b	obWidth(a0),d0
     //ext.w	d0

     //(neg.w	d0   )   FINDFLOOR DOES IT
     //(add.w	d0,d3)   LIKE THIS...
     //sub.w	d0,d3
     word obLeft = obX - obWidth;

     //lea	($FFFFF76A).w,a4
     signed short *v_anglebufferPtr2 = &FFFFF76A;

     //movea.w	#$10,a3     offset = 16;

     //move.w	#0,d6
     collisionFlags = 0;

     //moveq	#$D,d5
     solidnessBit = 0xD;

     signed short lfloorDist;
     //bsr.w	FindFloor
     FindFloor(&objects[0], obBottom, obLeft, solidnessBit, collisionFlags, lfloorDist, offset, v_anglebufferPtr2);

     //move.w	(sp)+,d0

     //move.b	#0,d2
     byte defaultAngle = 0;

     //move.b	($FFFFF76A).w,d3
     angle = (signed char)(FFFFF76A);
     lowSensor=rfloorDist;
     highSensor=lfloorDist;     
     

     //cmp.w	d0,d1
     //ble.s	loc_14DDE
     if (lfloorDist > rfloorDist)
     {
         //move.b	(v_anglebuffer).w,d2
         angle = (signed char)(v_anglebuffer);

         //exg	d0,d1
         highSensor = rfloorDist;
         lowSensor = lfloorDist;
     }
             
     //loc_14DDE:
     //btst	#0,d3
     if ((angle & 1) == 1)
         //move.b	d2,d3
         angle = defaultAngle;

}
void Sonic_HitWallLeft(signed short &wallDistL, byte &angle)
{

//; ---------------------------------------------------------------------------
//; Subroutine to	stop Sonic when	he jumps at a wall
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||

    //So there's a horizontal sensor line...
    //Sonic_HitWall:				; XREF: Sonic_Floor
    //move.w	obY(a0),d2
    //originating at his Y position...
    word obY = player.Y;

    //move.w	obX(a0),d3
    word obX = player.X;

    //loc_1504A:
    //subi.w	#$A,d3
    //eori.w	#$F,d3
    //and stretching from X-10 to X+10    (X-10 is relevant here for this is the position of LEFT sensor)
    word sensorLeft = (obX - 10) ^ 0xF;

    //lea	(v_anglebuffer).w,a4
    signed short *v_anglebufferPtr = &v_anglebuffer; 

    //movea.w	#-$10,a3
    signed short offset = -16;

    //move.w	#$800,d6
    word collisionFlags = 0x800;

    //moveq	#$E,d5
    byte solidnessBit = 0xE;
 
    //bsr.w	FindWall
    FindWall(&objects[0], obY, sensorLeft, solidnessBit, collisionFlags, wallDistL, offset, v_anglebufferPtr);

    //move.b	#$40,d2
    byte defaultAngle = 0x40;
    //bra.w	loc_14E0A
    //loc_14E0A:				; XREF: sub_14EB4
    //move.b	(v_anglebuffer).w,d3
    angle = (signed char)(v_anglebuffer);

    //btst	#0,d3
    //beq.s	locret_14E16
    if ((angle & 1)==1)
        //move.b	d2,d3
        angle = defaultAngle;

} //; End of function Sonic_HitWall

void Sonic_HitWallRight(signed short &wallDistR, byte &angle)
{
    //So there's a horizontal sensor line...
    //sub_14EB4:				; XREF: Sonic_Floor
    //move.w	obY(a0),d2
    //originating at his Y position...
    word obY = player.Y;

    //move.w	obX(a0),d3
    word obX = player.X;

    //loc_14EBC:
    //addi.w	#$A,d3
    //and stretching from X-10 to X+10    (X+10 is relevant here for this is the position of RIGHT sensor)
    word sensorRight = obX + 10;

    //lea	(v_anglebuffer).w,a4
    signed short *v_anglebufferPtr = &v_anglebuffer; 

    //movea.w	#$10,a3
    signed short offset = 16;

    //move.w	#0,d6
    word collisionFlags = 0;

    //moveq	#$E,d5
    byte solidnessBit = 0xE;
 
    //bsr.w	FindWall
    FindWall(&objects[0], obY, sensorRight, solidnessBit, collisionFlags, wallDistR, offset, v_anglebufferPtr);

    //move.b	#-$40,d2
    byte defaultAngle = -0x40;
    //bra.w	loc_14E0A
    //loc_14E0A:				; XREF: sub_14EB4
    //move.b	(v_anglebuffer).w,d3
    angle = (signed char)(v_anglebuffer);

    //btst	#0,d3
    //beq.s	locret_14E16
    if ((angle & 1)==1)
        //move.b	d2,d3
        angle = defaultAngle;
}

void Sonic_RollRepel()
{

//; ---------------------------------------------------------------------------
//; Subroutine to	push Sonic down	a slope	while he's rolling
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


    //Sonic_RollRepel:			; XREF: Obj01_MdRoll    //move.b	obAngle(a0),d0
    //addi.b	#$60,d0
    byte rollAngle = player.Angle + 0x60;

    //cmpi.b	#-$40,d0
    //bcc.s	locret_13544
    if (rollAngle > 0xC0)
    {
        //move.b	obAngle(a0),d0
        byte angle = player.Angle;
 
        signed short sine,cosine;
	//jsr	(CalcSine).l
        CalcSine(angle, sine, cosine);

	//muls.w	#$50,d0
        //asr.l	#8,d0
        signed short scaledSine = (sine * 0x50)/256;
		
        //tst.w	obInertia(a0)
        //bmi.s	loc_1353A
        if (player.Inertia >= 0)
        {
	    //tst.w	d0
	    //bpl.s	loc_13534
            //asr.l	#2,d0
            if (scaledSine < 0)
                scaledSine = scaledSine / 4;
  
            //loc_13534:
	    //add.w	d0,obInertia(a0)
            player.Inertia = player.Inertia + scaledSine;
        }
        //rts
        else
        {	
            //; ===========================================================================
            //loc_1353A:
	    //tst.w	d0
	    //bmi.s	loc_13540
	    //asr.l	#2,d0
            if (scaledSine > 0)
                scaledSine = scaledSine / 4;
       
            //loc_13540:
	    //add.w	d0,obInertia(a0)
            player.Inertia = player.Inertia + scaledSine;
        }

        //locret_13544:
	//rts	
    }
}   //; End of function Sonic_RollRepel

word rollspeedmax,rollspeedacc,rollspeeddec;
void Sonic_RollSpeed()
{

//Sonic_Move for rolling

//; ---------------------------------------------------------------------------
//; Subroutine to	change Sonic's speed as he rolls
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


    //Sonic_RollSpeed:			; XREF: Obj01_MdRoll
    //move.w	(v_sonspeedmax).w,d6
    //asl.w	#1,d6
    //move.w	(v_sonspeedacc).w,d5
    //asr.w	#1,d5
    //move.w	(v_sonspeeddec).w,d4
    //asr.w	#2,d4
    rollspeedmax=v_sonspeedmax*2;
    rollspeedacc=v_sonspeedacc/2;
    rollspeeddec=v_sonspeeddec/4;

    //tst.b	(f_jumponly).w
    //bne.w	loc_131CC
    if (f_jumponly==0)    {
        //tst.w	$3E(a0)
        //bne.s	@notright
        if (getobjvariableword(0x3E,objects[0])==0)
	{
	    //btst	#bitL,(v_jpadhold2).w ; is left being pressed?
	    //beq.s	@notleft	; if not, branch
	    //bsr.w	Sonic_RollLeft
            if ( (v_jpadhold2 & (1<<bitL)) == (1<<bitL) )
                Sonic_RollLeft();

	    //@notleft:
            //btst	#bitR,(v_jpadhold2).w ; is right being pressed?
	    //beq.s	@notright	; if not, branch
	    //bsr.w	Sonic_RollRight
            if ( (v_jpadhold2 & (1 << bitR)) == (1<<bitR) )
                Sonic_RollRight();

	    //@notright:
            #define newInertia obInertia
	    //move.w	obInertia(a0),d0
            signed short obInertia = player.Inertia;
           
	    //beq.s	loc_131AA
            if (obInertia != 0)
            {
		//bmi.s	loc_1319E
                if (obInertia > 0)
                {
		    //sub.w	d5,d0
                    newInertia = obInertia - rollspeedacc;

		    //bcc.s	loc_13198
                    //move.w	#0,d0
                    if (newInertia < 0)
                        newInertia = 0;
                
                    //loc_13198:
		    //move.w	d0,obInertia(a0)
		    player.Inertia = newInertia;

                    //bra.s	loc_131AA
                }
                else
                {
                    //; ===========================================================================

                    //loc_1319E:				; XREF: Sonic_RollSpeed
		    //add.w	d5,d0
		    newInertia = obInertia + rollspeedacc;
 
                    //bcc.s	loc_131A6
		    //move.w	#0,d0
                    if (newInertia < 0)
                        newInertia = 0;

                    //loc_131A6:
		    //move.w	d0,obInertia(a0) 
                    player.Inertia = newInertia;
                }
            }
            
            //loc_131AA:
	    //tst.w	obInertia(a0)	; is Sonic moving?
            //bne.s	loc_131CC	; if yes, branch
            if (player.Inertia == 0)
	    {
		//bclr	#2,obStatus(a0)
                player.Status = player.Status - (player.Status & 4);

		//move.b	#$13,obHeight(a0)
		player.Height = 19;

                //move.b	#9,obWidth(a0)
		player.Width = 9;

                //move.b	#id_Wait,obAnim(a0) ; use "standing" animation
		player.Anim = id_Wait;

                //subq.w	#5,obY(a0)
                player.Y = player.Y - 5;
            }

            //loc_131CC:
	    //move.b	obAngle(a0),d0
            byte angle = player.Angle;
            
            signed short sine,cosine;

	    //jsr	(CalcSine).l
            CalcSine(angle, sine, cosine);

	    //muls.w	obInertia(a0),d0
            //asr.l	#8,d0
            signed long newYVelocity=(sine*objects[0].Inertia)/256;

	    //move.w	d0,obVelY(a0)
            objects[0].VelocityY=newYVelocity;

	    //muls.w	obInertia(a0),d1
	    //asr.l	#8,d1
            signed long newXVelocity=(cosine*objects[0].Inertia)/256;

	    //cmpi.w	#$1000,d1
            //ble.s	loc_131F0
	    //move.w	#$1000,d1
            if (newXVelocity > 0x1000)
                newXVelocity = 0x1000;
            //loc_131F0:
	    //cmpi.w	#-$1000,d1
	    //bge.s	loc_131FA
	    //move.w	#-$1000,d1
            if (newXVelocity < -0x1000)
                newXVelocity = -0x1000;

            //loc_131FA:
	    //move.w	d1,obVelX(a0)
            player.VelocityX = newXVelocity;

	    //bra.w	loc_1300C
            Sonic_StopAtWalls();
        }
    }
}  //; End of function Sonic_RollSpeed


//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||

void Sonic_RollLeft()
{
    //Sonic_RollLeft:				; XREF: Sonic_RollSpeed
    #define newInertia obInertia
    //move.w	obInertia(a0),d0
    signed short obInertia = player.Inertia;

    //beq.s	loc_1320A
    if (obInertia == 0 || obInertia < 0)
    {
        //loc_1320A:
        //bset	#0,obStatus(a0)
        player.Status = player.Status | 1;

	//move.b	#id_Roll,obAnim(a0) ; use "rolling" animation
        player.Anim = id_Roll;
	 
   	//rts
    }
    else
    {
        //bpl.s	loc_13218
        //; ===========================================================================
        //loc_13218:
	//sub.w	d4,d0
        newInertia = obInertia - rollspeeddec;

	//bcc.s	loc_13220
        //move.w	#-$80,d0
        if (newInertia < 0)
            newInertia = -0x80;
		
        //loc_13220:
	//move.w	d0,obInertia(a0)
        player.Inertia = newInertia;
    }
    //rts	
} //; End of function Sonic_RollLeft


//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||

void Sonic_RollRight()
{
    //Sonic_RollRight:			; XREF: Sonic_RollSpeed
    #define newInertia obInertia
    //move.w	obInertia(a0),d0'
    signed short obInertia = player.Inertia;

    //bmi.s	loc_1323A
    if (obInertia > 0)
    {
        //bclr	#0,obStatus(a0)
	player.Status = player.Status - (player.Status & 1);

       	//move.b	#id_Roll,obAnim(a0) ; use "rolling" animation
	player.Anim = id_Roll;
	
    }  //rts
    else
    {	
        //; ===========================================================================
        //loc_1323A:
	//add.w	d4,d0
        newInertia = obInertia + rollspeeddec;

	//bcc.s	loc_13242
        //move.w	#$80,d0
        if (newInertia < 0)
            newInertia = 0x80;

        //loc_13242:
	//move.w	d0,obInertia(a0)
        player.Inertia = newInertia;
   
    }   //rts	
}  //; End of function Sonic_RollRight

//; ---------------------------------------------------------------------------
//; Subroutine to check how far sonic is from the floor
//; ---------------------------------------------------------------------------

void Sonic_CheckFloor(signed short &sensorHighestHeight, byte &sensorHighestAngle)	//; XREF: Sonic_Floor
{
     //move.w	obY(a0),d2
     //move.w	obX(a0),d3
     //moveq	#0,d0
     word obY = objects[0].Y;
     word obX = objects[0].X;

     //move.b	obHeight(a0),d0
     //ext.w	d0
     word obHeight = objects[0].Height;
     //add.w	d0,d2
     word obBottom = obY + obHeight;
     
     //move.b	obWidth(a0),d0
     //ext.w	d0
     word obWidth = objects[0].Width;

     //add.w	d0,d3
     word obRight = obX + obWidth;

     //lea	(v_anglebuffer).w,a4
     signed short *v_anglebufferPtr = &v_anglebuffer;

     //movea.w	#$10,a3
     word offset = 16;

     //move.w	#0,d6
     word collisionFlags = 0;

     //moveq	#$D,d5
     byte solidnessBit = 0xD;
 
     signed short floorDistR;
     //bsr.w	FindFloor
     FindFloor(&objects[0], obBottom, obRight, solidnessBit, collisionFlags, floorDistR, offset, v_anglebufferPtr);
     //move.w	d1,-(sp)
	
     //move.w	obY(a0),d2         //recalculations
     //move.w	obX(a0),d3
     //moveq	#0,d0
     //move.b	obHeight(a0),d0
     //ext.w	d0
     //add.w	d0,d2              
     //move.b	obWidth(a0),d0
     //ext.w	d0                 //---------------

     //sub.w	d0,d3
     word obLeft = obX - obWidth;

     //lea	($FFFFF76A).w,a4
     signed short *v_anglebufferPtr2 = &FFFFF76A;

     //movea.w	#$10,a3
     offset = 16;

     //move.w	#0,d6
     collisionFlags = 0;

     //moveq	#$D,d5
     solidnessBit = 0xD;
	
     signed short floorDistL;
     //bsr.w	FindFloor
     FindFloor(&objects[0], obBottom, obLeft, solidnessBit, collisionFlags, floorDistL, offset, v_anglebufferPtr2);

     //move.w	(sp)+,d0           no need to use stack..
     //move.b	#0,d2              no need to use zero

     //Whichever sensor finds the highest height, Sonic's Y is set to that height minus 20 pixels. 
     //His angle is also set to the angle of the solid tile that returned the highest height.

     //loc_14DD0:
     //move.b	($FFFFF76A).w,d3
     sensorHighestAngle = (signed char)(FFFFF76A);
     sensorHighestHeight = floorDistR;

     //cmp.w	d0,d1                      
     if (floorDistL > floorDistR)
     {
        //ble.s	loc_14DDE
	//move.b	(v_anglebuffer).w,d3
        sensorHighestAngle = (signed char)(v_anglebuffer);
	//exg	d0,d1
	sensorHighestHeight = floorDistL;         //if the only distance we use is the highset angle then we return 
     }

//loc_14DDE:
     //btst	#0,d3
     //beq.s	locret_14DE6
     if ((sensorHighestAngle & 1) == 1)
     //move.b	d2,d3
          sensorHighestAngle = 0;

//locret_14DE6:
//		rts	

//; End of function Sonic_HitFloor
}

//; ---------------------------------------------------------------------------
//; Subroutine to check how far sonic is from the ceiling in right wall mode 
//;    (IN RIGHT WALL MODE THIS IS THE "FLOOR")
//; ---------------------------------------------------------------------------

void Sonic_CheckRightCeiling(signed short &sensorHighestHeight, byte &sensorHighestAngle)    //sub_14E50
{
     //move.w	obY(a0),d2
     //move.w	obX(a0),d3
     //moveq	#0,d0
     word obY = objects[0].Y;
     word obX = objects[0].X;

     //move.b	obWidth(a0),d0
     //ext.w	d0
     word obWidth = objects[0].Width;
     //sub.w	d0,d2
     word obTop = obY - obWidth;
     
     //move.b	obHeight(a0),d0
     //ext.w	d0
     word obHeight = objects[0].Height;

     //add.w	d0,d3
     word obRight = obX + obHeight;

     //lea	(v_anglebuffer).w,a4
     signed short *v_anglebufferPtr = &v_anglebuffer;

     //movea.w	#$10,a3
     word offset = 16;

     //move.w	#0,d6
     word collisionFlags = 0;

     //moveq	#$E,d5
     byte solidnessBit = 0xE;
 
     signed short rceilDistR;
     //bsr.w	FindWall
     FindWall(&objects[0], obTop, obRight, solidnessBit, collisionFlags, rceilDistR, offset, v_anglebufferPtr);
     //move.w	d1,-(sp)
	
     //move.w	obY(a0),d2         //recalculations
     //move.w	obX(a0),d3
     //moveq	#0,d0              //--------------
     //move.b	obWidth(a0),d0
     //ext.w	d0
     //add.w	d0,d2
     word obBottom = obY + obWidth;
            
     //move.b	obHeight(a0),d0    //recalculations
     //ext.w	d0                 
     //add.w	d0,d3              //--------------
    
     //lea	($FFFFF76A).w,a4
     signed short *v_anglebufferPtr2 = &FFFFF76A;

     //movea.w	#$10,a3
     offset = 16;

     //move.w	#0,d6
     collisionFlags = 0;

     //moveq	#$E,d5
     solidnessBit = 0xE;
	
     signed short rceilDistL;
     //bsr.w	FindWall
     FindWall(&objects[0], obBottom, obRight, solidnessBit, collisionFlags, rceilDistL, offset, v_anglebufferPtr2);

     //move.w	(sp)+,d0           no need to use stack..
     //move.b	#$-$40,d2              no need to use zero
     const char defaultAngle = -0x40;

     //loc_14DD0:
     //move.b	($FFFFF76A).w,d3
     sensorHighestAngle = (signed char)(FFFFF76A);
     sensorHighestHeight = rceilDistR;

     //cmp.w	d0,d1                      
     if (rceilDistL > rceilDistR)
     {
        //ble.s	loc_14DDE
	//move.b	(v_anglebuffer).w,d3
        sensorHighestAngle = (signed char)(v_anglebuffer);
	//exg	d0,d1
	sensorHighestHeight = rceilDistL;         //if the only distance we use is the highset angle then we return 
     }

//loc_14DDE:
     //btst	#0,d3
     //beq.s	locret_14DE6
     if ((sensorHighestAngle & 1) == 1)
     //move.b	d2,d3
          sensorHighestAngle = defaultAngle;

//locret_14DE6:
//		rts	

}

void Sonic_CheckLeftCeiling(signed short &sensorHighestHeight, byte &sensorHighestAngle)    //sub_14D48
{
     //move.w	obY(a0),d2
     //move.w	obX(a0),d3
     //moveq	#0,d0
     word obY = objects[0].Y;
     word obX = objects[0].X;

     //move.b	obWidth(a0),d0
     //ext.w	d0
     word obWidth = objects[0].Width;
     //sub.w	d0,d2
     word obTop = obY - obWidth;
     
     //move.b	obHeight(a0),d0
     //ext.w	d0
     word obHeight = objects[0].Height;

     //sub.w	d0,d3
     word obLeft = (obX - obHeight) ^ 0xF;

     //eori.w	#$F,d3             //diff
     
     //lea	(v_anglebuffer).w,a4
     signed short *v_anglebufferPtr = &v_anglebuffer;

     //movea.w	#-$10,a3
     signed short offset = -16;

     //move.w	#$800,d6
     word collisionFlags = 0x800;

     //moveq	#$E,d5
     byte solidnessBit = 0xE;
 
     signed short lceilDistR;
     //bsr.w	FindWall
     FindWall(&objects[0], obTop, obLeft, solidnessBit, collisionFlags, lceilDistR, offset, v_anglebufferPtr);
     //move.w	d1,-(sp)
	
     //move.w	obY(a0),d2         //recalculations
     //move.w	obX(a0),d3
     //moveq	#0,d0              //--------------
     //move.b	obWidth(a0),d0
     //ext.w	d0
     //add.w	d0,d2
     word obBottom = obY + obWidth;
            
     //move.b	obHeight(a0),d0    //recalculations
     //ext.w	d0                 
     //add.w	d0,d3              //--------------
    

     //lea	($FFFFF76A).w,a4
     signed short *v_anglebufferPtr2 = &FFFFF76A;

     //movea.w	#-$10,a3
     offset = -16;

     //move.w	#$800,d6
     collisionFlags = 0x800;

     //moveq	#$E,d5
     solidnessBit = 0xE;
	
     signed short lceilDistL;
     //bsr.w	FindWall
     FindWall(&objects[0], obBottom, obLeft, solidnessBit, collisionFlags, lceilDistL, offset, v_anglebufferPtr2);

     //move.w	(sp)+,d0           no need to use stack..
     //move.b	#$40,d2              no need to use zero
     const char defaultAngle = 0x40;

     //loc_14DD0:
     //move.b	($FFFFF76A).w,d3
     sensorHighestAngle = (signed char)(FFFFF76A);
     sensorHighestHeight = lceilDistR;

     //cmp.w	d0,d1                      
     if (lceilDistL > lceilDistR)
     {
        //ble.s	loc_14DDE
	//move.b	(v_anglebuffer).w,d3
        sensorHighestAngle = (signed char)(v_anglebuffer);
	//exg	d0,d1
	sensorHighestHeight = lceilDistL;         //if the only distance we use is the highset angle then we return 
     }

//loc_14DDE:
     //btst	#0,d3
     //beq.s	locret_14DE6
     if ((sensorHighestAngle & 1) == 1)
     //move.b	d2,d3
          sensorHighestAngle = defaultAngle;

//locret_14DE6:
//		rts	

}

void Sonic_CheckCeiling(signed short &sensorHighestHeight, byte &sensorHighestAngle)    //sub_14D48
{
     //move.w	obY(a0),d2
     //move.w	obX(a0),d3
     //moveq	#0,d0
     word obY = objects[0].Y;
     word obX = objects[0].X;

     //move.b	obHeight(a0),d0
     //ext.w	d0
     word obHeight = objects[0].Height;
     //sub.w	d0,d2
     //eori.w #$F, d2
     word obBottom = (obY - obHeight) ^ 0xF; //logical XOR is for flip position upside-down within the current 16x16 block?;
     
     //move.b	obWidth(a0),d0
     //ext.w	d0
     word obWidth = objects[0].Width;

     //add.w	d0,d3
     word obRight = obX + obWidth;

     //lea	(v_anglebuffer).w,a4
     signed short *v_anglebufferPtr = &v_anglebuffer;

     //movea.w	#$-10,a3
     signed short offset = -16;

     //move.w	#$1000,d6
     word collisionFlags = 0x1000;

     //moveq	#$E,d5
     byte solidnessBit = 0xE;
 
     signed short ceilDistR;
     //bsr.w	FindFloor
     FindFloor(&objects[0], obBottom, obRight, solidnessBit, collisionFlags, ceilDistR, offset, v_anglebufferPtr);
     //move.w	d1,-(sp)
	
     //move.w	obY(a0),d2         //recalculations
     //move.w	obX(a0),d3
     //moveq	#0,d0
     //move.b	obHeight(a0),d0
     //ext.w	d0
     //sub.w	d0,d2              
     //move.b	obWidth(a0),d0
     //ext.w	d0                 //---------------

     //sub.w	d0,d3
     word obLeft = (obX - obWidth);

     //lea	($FFFFF76A).w,a4
     signed short *v_anglebufferPtr2 = &FFFFF76A;

     //movea.w	#-$10,a3
     offset = -16;

     //move.w	#$1000,d6
     collisionFlags = 0x1000;

     //moveq	#$E,d5
     solidnessBit = 0xE;
	
     signed short ceilDistL;
     //bsr.w	FindFloor
     FindFloor(&objects[0], obBottom, obLeft, solidnessBit, collisionFlags, ceilDistL, offset, v_anglebufferPtr2);

     //move.w	(sp)+,d0           no need to use stack..
     //move.b	#-$80,d2
     const char defaultAngle = -0x80;             

     //Whichever sensor finds the highest height, Sonic's Y is set to that height minus 20 pixels. 
     //His angle is also set to the angle of the solid tile that returned the highest height.

     //loc_14DD0:
     //move.b	($FFFFF76A).w,d3
     sensorHighestAngle = (signed char)(FFFFF76A);
     sensorHighestHeight = ceilDistR;

     //cmp.w	d0,d1                      
     if (ceilDistL > ceilDistR)
     {
        //ble.s	loc_14DDE
	//move.b	(v_anglebuffer).w,d3
        sensorHighestAngle = (v_anglebuffer);
	//exg	d0,d1
	sensorHighestHeight = ceilDistL;         //if the only distance we use is the highset angle then we return 
     }

//loc_14DDE:
     //btst	#0,d3
     //beq.s	locret_14DE6
     if ((sensorHighestAngle & 1) == 1)
     //move.b	d2,d3
          sensorHighestAngle = defaultAngle;

//locret_14DE6:
//		rts	

}

extern byte v_lvllayout[];
//; ---------------------------------------------------------------------------
//; Subroutine to	make Sonic run around loops (GHZ/SLZ)
//; ---------------------------------------------------------------------------

//Sonic_Loops:				; XREF: Obj01_Control
void Sonic_Loops()
{
        //cmpi.b	#id_SLZ,(v_zone).w ; is level SLZ ?
	//beq.s	@isstarlight	; if yes, branch
	//tst.b	(v_zone).w	; is level GHZ ?
	//bne.w	@noloops	; if not, branch
         

	//@isstarlight:
        //if (v_zone == id_GHZ || v_zone == id_SLZ)
        //{
	    //move.w	obY(a0),d0
	    //lsr.w	#1,d0
	    //andi.w	#$380,d0
            //move.b	obX(a0),d1
	    //andi.w	#$7F,d1
	    //add.w	d1,d0
            word chunkYOffset = (player.Y >> 1) & 0x380;               //get y-pos. of bottom edge of object (to calculate y offset into level layout)
            word chunkXOffset = (player.X >> 8) & 0x7F;                      //get x-pos. of object (to calculate x offset into level layout)
            word layoutIndex = chunkXOffset + chunkYOffset;             //combine
	
	    //lea	(v_lvllayout).w,a1
            //move.b	(a1,d0.w),d1	; d1 is	the 256x256 tile Sonic is currently on
            byte cur256 = v_lvllayout[layoutIndex];

            //cmp.b	(v_256roll1).w,d1 ; is Sonic on a "roll tunnel" tile?
	    //beq.w	Sonic_ChkRoll	; if yes, branch
	    //cmp.b	(v_256roll2).w,d1
	    //beq.w	Sonic_ChkRoll
            if (cur256 == v_256roll1 || cur256 == v_256roll2)
            {

            }
	    else
            {
                //cmp.b	(v_256loop1).w,d1 ; is Sonic on a loop tile?
		//beq.s	@chkifleft	; if yes, branch
                if (cur256 != v_256loop1)
                {
                    //cmp.b	(v_256loop2).w,d1
		    //beq.s	@chkifinair
                    if (cur256 == v_256loop2)
                    {
                        
                        //@chkifinair:
		        //btst	#1,obStatus(a0)	; is Sonic in the air?
		        //beq.s	@chkifleft	; if not, branch
                        if ((player.Status & 2) == 2)
                        {
                            //bclr	#6,obRender(a0)	; return Sonic to high plane	
                            player.Render = player.Render - (player.Render & 64);

                            //rts
                            return;
                        }
                    }   
                }
                
                //@chkifleft:
		//move.w	obX(a0),d2
		word playerX = player.X;
                
                byte loopX = playerX & 0xFF;
                 //cmpi.b	#$2C,d2
		//bcc.s	@chkifright
                if (loopX < 0x2C)
                {
		    //bclr	#6,obRender(a0)	; return Sonic to high plane	
                    player.Render = player.Render - (player.Render & 64);

                    //rts
                    return;
                }
                
                //@chkifright:
		//cmpi.b	#$E0,d2
		//bcs.s	@chkangle1
                if (loopX >= 0xE0)
                {
		    //bset	#6,obRender(a0)	; send Sonic to	low plane
                    player.Render = player.Render | 64;

                    //rts
                    return;
                }

                //@chkangle1:
		//btst	#6,obRender(a0) ; is Sonic on low plane?
                //bne.s	@chkangle2	; if yes, branch
		if ((player.Render & 64) != 64)
                {
                    //move.b	obAngle(a0),d1
                    byte angle = player.Angle;

		    //beq.s	@done
		    //cmpi.b	#$80,d1		; is Sonic upside-down?
		    //bhi.s	@done		; if yes, branch
                    if (angle != 0 && angle < 0x80)    //sonic is right-side up
                    {
		        //bset	#6,obRender(a0)	; send Sonic to	low plane
                        player.Render = player.Render | 64;
                    }
 
		    //rts
                    return;
                }

                //@chkangle2:
		//move.b	obAngle(a0),d1
                byte angle = player.Angle;

		//cmpi.b	#$80,d1		; is Sonic upright?
                //bls.s	@done		; if yes, branch
                if (angle >= 0x80)       //sonic is upside-down
                {
		    //bclr	#6,obRender(a0)	; send Sonic to	high plane
                    player.Render = player.Render - (player.Render & 64);
                }
			
            }
        //}
        //@noloops:
        //@done:
	//rts
}   //; End of function Sonic_Loops


//; ---------------------------------------------------------------------------
//; Sonic	when he	gets hurt
//; ---------------------------------------------------------------------------

//Sonic_Hurt:	; Routine 4
void Sonic_Hurt()
{
    //jsr	SpeedToPos
    SpeedToPos(&player);

    //addi.w	#$30,obVelY(a0)
    player.VelocityY = player.VelocityY + 48;

    //btst	#6,obStatus(a0)
    //beq.s	loc_1380C
    if ((player.Status & 32) == 32)
    {
        //subi.w	#$20,obVelY(a0)
        player.VelocityY = player.VelocityY - 32;
    }

    //loc_1380C:
    //bsr.w	Sonic_HurtStop
    Sonic_HurtStop();

    //bsr.w	Sonic_LevelBound
    Sonic_LevelBound();

    //bsr.w	Sonic_RecordPosition
    //Sonic_RecordPosition();

    //bsr.w	Sonic_Animate
    Sonic_Animate();

    //bsr.w	Sonic_LoadGfx
    Sonic_LoadGfx();

    //jmp	DisplaySprite
    DisplaySprite(&player);
}

//; ---------------------------------------------------------------------------
//; Subroutine to	stop Sonic falling after he's been hurt
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


//Sonic_HurtStop:				; XREF: Sonic_Hurt
void Sonic_HurtStop()
{
    //move.w	(v_limitbtm2).w,d0
    //addi.w	#$E0,d0
    word limitbtm = v_limitbtm2 + 0xE0;

    //cmp.w	obY(a0),d0
    //bcs.w	KillSonic
    if (limitbtm < player.Y)
    {
        //KillSonic();
    }    

    //bsr.w	Sonic_Floor
    Sonic_Floor();

    //btst	#1,obStatus(a0)
    //bne.s	locret_13860
    if ((player.Status & 1) == 0)
    {
        //moveq	#0,d0
	//move.w	d0,obVelY(a0)
        player.VelocityY = 0;

	//move.w	d0,obVelX(a0)
        player.VelocityX = 0;

        //move.w	d0,obInertia(a0)
        player.Inertia = 0;

	//move.b	#id_Walk,obAnim(a0)
        player.Anim = id_Walk;

	//subq.b	#2,obRoutine(a0)
        player.Routine = player.Routine - 2;

	//move.w	#$78,$30(a0)
        setobjvariableword(0x30,player,0x78);
 
    }
    //locret_13860:
    //rts	
}   //; End of function Sonic_HurtStop

void loadframe(byte *aniScript)
{
    //moveq	#0,d1
    //move.b	obAniFrame(a0),d1 ; load current frame number
    byte curFrame=player.AniFrame;            //load current frame number

    
    //move.b	1(a1,d1.w),d0	; read sprite number from script
    byte curSprite=aniScript[1+curFrame];     //read sprite number from script
	
    if (curSprite < 0x80)                        //if animation is not complete          
    { 
       //bmi.s	@end_FF		; if animation is complete, branch

       //@next:
       //move.b	d0,obFrame(a0)	; load sprite number
       player.Frame=curSprite;                //load sprite number
       
       //addq.b	#1,obAniFrame(a0) ; next frame number
       player.AniFrame=player.AniFrame+1;

       //@delay:
       //rts
    }
    else
    {                                         //if animation is complete	
    //; ===========================================================================

    //@end_FF:
    
    //addq.b	#1,d0		; is the end flag = $FF	?
    //bne.s	@end_FE		; if not, branch

        if (curSprite==0xFF)
        {
           //move.b	#0,obAniFrame(a0) ; restart the animation
           player.AniFrame=0;         //restart the animation
           
           //move.b	1(a1),d0	; read sprite number
           curSprite=aniScript[1];    //read sprite number
           //bra.s	@next
           
           //@next...
           player.Frame=curSprite;                //load sprite number
       
           //addq.b	#1,obAniFrame(a0) ; next frame number
           player.AniFrame=player.AniFrame+1;
        }
        else if (curSprite==0xFE)
        {
             
//; ===========================================================================

            //@end_FE:
            //		addq.b	#1,d0		; is the end flag = $FE	?
            
            //		bne.s	@end_FD		; if not, branch
            
            //		move.b	2(a1,d1.w),d0	; read the next	byte in	the script
            byte jumpBack=aniScript[2+curFrame];   //read next byte in script
            //		sub.b	d0,obAniFrame(a0) ; jump back d0 bytes in the script
            player.AniFrame=player.AniFrame-jumpBack;
            
            //		sub.b	d0,d1
            curFrame=curFrame-jumpBack;
            //		move.b	1(a1,d1.w),d0	; read sprite number
            curSprite=aniScript[1+curFrame];
            
            //		bra.s	@next
              //@next...
           player.Frame=curSprite;                //load sprite number
       
           //addq.b	#1,obAniFrame(a0) ; next frame number
           player.AniFrame=player.AniFrame+1;
      }
      else if (curSprite==0xFD)
      {
           player.Anim=aniScript[2+curFrame];   //read next byte, run that animation
      }
   }
    //; ===========================================================================
    
    //@end_FD:
              
    		//addq.b	#1,d0		; is the end flag = $FD	?
    		//bne.s	@end		; if not, branch
    		//move.b	2(a1,d1.w),obAnim(a0) ; read next byte, run that animation
    
    	//@end:
    	//	rts	
    //; ===========================================================================
}

void Sonic_Animate()
{
//; ---------------------------------------------------------------------------
//; Subroutine to	animate	Sonic's sprites
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


//Sonic_Animate:				; XREF: Obj01_Control; et al

//		lea	(Ani_Sonic).l,a1
//		moveq	#0,d0
        if (player.Anim!=player.NextAni) //if animation is set to restart
        {
             player.NextAni=player.Anim;//set to "no restart"
             player.AniFrame=0;         //reset animation
             player.TimeFrame=0;        //reset frame duration
        }
        //move.b	obAnim(a0),d0
		//cmp.b	obNextAni(a0),d0 ; is animation set to restart?
		//beq.s	@do		; if not, branch
		//move.b	d0,obNextAni(a0) ; set to "no restart"
		//move.b	#0,obAniFrame(a0) ; reset animation
		//move.b	#0,obTimeFrame(a0) ; reset frame duration

	    //@do:
		//add.w	d0,d0
		byte *animationScript=Ani_Sonic[player.Anim];
		
        //adda.w	(a1,d0.w),a1	; jump to appropriate animation	script
		//move.b	(a1),d0
		byte animationNum=animationScript[0];

		#define frameDuration animationNum
		
		if (animationNum<0x80)
		{
            //bmi.s	@walkrunroll	; if animation is walk/run/roll/jump, branch
    		
            
            //move.b	obStatus(a0),d1
    		byte horizFlag=player.Status&1;
    		player.Render=(player.Render&0xFC)|horizFlag;
    		
            //andi.b	#1,d1
    		//andi.b	#$FC,obRender(a0)
    		//or.b	d1,obRender(a0)
    		//subq.b	#1,obTimeFrame(a0) ; subtract 1 from frame duration
    		player.TimeFrame= player.TimeFrame-1;     //subtract 1 from frame duration
    		
            if (player.TimeFrame <= 0)                //if no time remains in frame duration
            { 
                //bpl.s	@delay		; if time remains, branch
        	//move.b	d0,obTimeFrame(a0) ; load frame duration
                player.TimeFrame=frameDuration;
                
                loadframe(animationScript);
            }
         }
         else          //animationNum is negative..
         {
             

            //@walkrunroll:
    	    //subq.b	#1,obTimeFrame(a0) ; subtract 1 from frame duration
    	    player.TimeFrame=player.TimeFrame-1;
    		
            //bpl.s	@delay		            //; if time remains, branch
    	    if (player.TimeFrame>=0) { return; }  //if time still remains in the animation
            
            //addq.b	#1,d0		; is animation walking/running?
    	    //bne.w	@rolljump	; if not, branch
    		
    	    if (animationNum==0xFF)
            {
               //moveq	#0,d1             
    	       byte oriInvert=0;          
    		                          
               //move.b	obAngle(a0),d0	; get Sonic's angle
    	       signed char angle=player.Angle;  
    		   
               //move.b	obStatus(a0),d2
    	       byte status=player.Status;
    		   
               //andi.b	#1,d2		; is Sonic mirrored horizontally (not render-wise but status-wise i.e. orientation)?
               byte orientation = status & 1;
    	       if (orientation!=1)        //if sonic not mirrored horizontally
    	           angle=~angle;          //reverse angle    
               //bne.s	@flip		; if yes, branch
    	       //not.b	d0		; reverse angle
    
               //@flip:
    	       //addi.b	#$10,d0		; add $10 to angle
    	       angle=angle+0x10;
    		   
               //bpl.s	@noinvert	; if angle is $0-$7F, branch
    	       if (angle < 0)        
                  oriInvert=3;           //bit for orientation inverted and vertical flip set..
               //moveq	#3,d1
               
    	       //@noinvert:
    	       //andi.b	#$FC,obRender(a0)
    	       player.Render=player.Render&0xFC;     //clear bits 0&1 (render flip horizontal and vertical)
    		   
               //eor.b	d1,d2
    	       byte flipBits=orientation^oriInvert;  //since orientation is 1 bit (horiz)...
                                                     // xor'ing with oriInvert will yield the proper 2 bits for render flip vertical
                                                     // and then horizontal
               //or.b	d2,obRender(a0)
    	       player.Render=player.Render|flipBits; //set bits accordingly
    		   
               //btst	#5,obStatus(a0)	; is Sonic pushing something?
    	       if ((player.Status & 32)!=32)     //if sonic is not pushing anything
               {
                  
            
                    //bne.w	@push		; if yes, branch
            	    //lsr.b	#4,d0		; divide angle by $10
            	    //andi.b	#6,d0		; angle	must be	0, 2, 4	or 6
            	    byte angleFrame=((byte)angle/0x10) & 6;  //divide angle by ten and anded with 6 value is either 0,2,4,6
                    
                    //move.w	obInertia(a0),d2 ; get Sonic's speed
            	    signed short speed=player.Inertia; //get sonic's speed
           		    
                    if (speed<0) { speed=-speed; }    //modulus speed
                    //bpl.s	@nomodspeed
            	    //neg.w	d2		; modulus speed
    
    	            //@nomodspeed:
                    //lea	(SonAni_Run).l,a1 ; use	running	animation
    		    animationScript=SonAni_Run;
    		        
                    //cmpi.w	#$600,d2	; is Sonic at running speed?
    		    if (speed < 0x600)      //if sonic not at running speed
    		    {
                        //bcc.s	@running	; if yes, branch
        
        		//lea	(SonAni_Walk).l,a1 ; use walking animation
        		animationScript=SonAni_Walk;
                        
                        //move.b	d0,d1
        		//lsr.b	#1,d1
        		//add.b	d1,d0
                        angleFrame=(angleFrame/2)+angleFrame;
                    }
                    
    	            //@running:
    		    //add.b	d0,d0
    		    //move.b	d0,d3
    		    signed char frameAdd=angleFrame*2;
                    
                    //neg.w	d2
    		    //addi.w	#$800,d2
    		    speed=0x800-speed;
    		        
                    //bpl.s	@belowmax
    		    //moveq	#0,d2		; max animation speed
                    if (speed < 0) { speed=0; }    //max animation speed
                    
    	            //@belowmax:
    		    //lsr.w	#8,d2
    		    //move.b	d2,obTimeFrame(a0) ; modify frame duration
    		    player.TimeFrame=speed/256;
    		        
                    //bsr.w	@loadframe
    		    loadframe(animationScript);
    		        
                    //add.b	d3,obFrame(a0)	; modify frame number
    		    player.Frame=player.Frame+frameAdd;
               }
               
              else
              {
                   //push:
		   //move.w	obInertia(a0),d2 ; get Sonic's speed
		   signed short speed = player.Inertia;
		           
                   //bmi.s	@negspeed
		   //neg.w	d2
                   if (speed > 0) { speed=-speed; }
                   
	           //@negspeed:
		   //addi.w	#$800,d2
		   speed=0x800+speed;
		           
                   //bpl.s	@belowmax3	
		           
                   //moveq	#0,d2
                   if (speed<0) { speed=0; }

	           //@belowmax3:
		   //lsr.w	#6,d2
		   //move.b	d2,obTimeFrame(a0) ; modify frame duration
		   player.TimeFrame=speed/64;
		           
                   //lea	(SonAni_Push).l,a1
		   animationScript=SonAni_Push;
		           
                   //move.b	obStatus(a0),d1
		   //andi.b	#1,d1
		   //andi.b	#$FC,obRender(a0)
		   //or.b	d1,obRender(a0)
		   byte flag=(player.Status&1);
		   player.Render=(player.Render&0xFC)|flag;
		                 
                   loadframe(animationScript);
                }
            }
    //; ======//=====================================================================
            else if (animationNum==0xFE) 
            {                                                                             
                //@rolljump:
    		//addq.b	#1,d0		; is animation rolling/jumping?
    		//bne.s	@push		; if not, branch
    		
                //move.w	obInertia(a0),d2 ; get Sonic's speed
    	        signed short speed=player.Inertia;
    	        
        	//bpl.s	@nomodspeed2
    		//neg.w	d2
                if (speed < 0)
                    speed=-speed;
                
    	        //@nomodspeed2:
    		animationScript=SonAni_Roll2; //lea	(SonAni_Roll2).l,a1 ; use fast animation
    		    
                //cmpi.w	#$600,d2	; is Sonic moving fast?
    		if (speed < 0x600)
    		{
    		        
                    //bcc.s	@rollfast	; if yes, branch
    		    //lea	(SonAni_Roll).l,a1 ; use slower	animation
                    animationScript=SonAni_Roll;            //use animation script
                }   
	            //@rollfast:
		        
                //neg.w	d2
                //addi.w	#$400,d2
		speed = 0x400 - speed;
		
                //bpl.s	@belowmax2
		if (speed < 0)
                   speed=0;
                   
                //moveq	#0,d2

	        //@belowmax2:
		//lsr.w	#8,d2
		speed=speed/256;
        
                //move.b	d2,obTimeFrame(a0) ; modify frame duration
		player.TimeFrame=speed;
		        
                //move.b	obStatus(a0),d1
		//andi.b	#1,d1
		//andi.b	#$FC,obRender(a0)
		//or.b	d1,obRender(a0)
		byte flag=(player.Status&1);
		player.Render=(player.Render&0xFC)|flag;
		        
		//bra.w	@loadframe
                loadframe(animationScript);
                
                //; ===========================================================================
           }
           else
           {
                   //move.w	obInertia(a0),d2 ; get Sonic's speed
		   signed short speed = player.Inertia;
		           
                   //bmi.s	@negspeed
		   //neg.w	d2
                   if (speed > 0) { speed=-speed; }
                   
	           //@negspeed:
		   //addi.w	#$800,d2
		   speed=0x800+speed;
		           
                   //bpl.s	@belowmax3	         
                   //moveq	#0,d2
                   if (speed<0) { speed=0; }

	           //@belowmax3:
		   //lsr.w	#6,d2
		   //move.b	d2,obTimeFrame(a0) ; modify frame duration
		   player.TimeFrame=speed/64;
		           
                   //lea	(SonAni_Push).l,a1
		   animationScript=SonAni_Push;
		           
                   //move.b	obStatus(a0),d1
		   //andi.b	#1,d1
		   //andi.b	#$FC,obRender(a0)
		   //or.b	d1,obRender(a0)
		   byte flag=(player.Status&1);
		   player.Render=(player.Render&0xFC)|flag;
		                   
                   loadframe(animationScript);
           
           }

      }
}

void Sonic_LoadGfx()
{
    byte frame=player.Frame;

    if (frame!=v_sonframenum)	//has frame not changed?
    {
        v_sonframenum = frame;
        
	byte **SonicDynPLCPtr=SonicDynPLC;
	byte *curFramePtr=SonicDynPLCPtr[frame];       //+frame*2;
		
	//moveq	#0,d1
	signed char numEntries=*(curFramePtr++)-1;
		
	//move.b	(a2)+,d1	; read "number of entries" value
	//subq.b	#1,d1
			
	if (numEntries>=0)
	{
	   //bmi.s	@nochange	; if zero, branch
	   //lea	(v_sgfx_buffer).w,a3
	   long *v_sgfx_bufferPtr=(long*)v_sgfx_buffer;
	
	   //move.b	#1,(f_sonframechg).w ; set flag for Sonic graphics DMA
	   f_sonframechg=1;

	   for (int entryLp=0; entryLp<=numEntries; entryLp++)
	   {
	      //@readentry:
	      //moveq	#0,d2
	
	      //move.b	(a2)+,d2	;read next entry
	      //move.w	d2,d0
	      byte entry=*(curFramePtr++);
	      word numTiles=entry/16;

	      //lsr.b	#4,d0
	      //lsl.w	#8,d2
	      byte entryTwo=*(curFramePtr++);
	      word bothEntries=(entry<<8)+entryTwo;
	
	      //move.b	(a2)+,d2
	      //lsl.w	#5,d2
	      word tileIndex=bothEntries*32;

	      //lea	(Art_Sonic).l,a1
	      //adda.l	d2,a1
	      long *tileAddress=(long*)(Art_Sonic+tileIndex);

	      for (int lp=0; lp<=numTiles; lp++)
	      {
		   //@loadtile:
		   //movem.l	(a1)+,d2-d6/a4-a6
		   //movem.l	d2-d6/a4-a6,(a3)
		   for (int count=0; count<8; count++)
	              *(v_sgfx_bufferPtr++)=*(tileAddress++);	//++ used here to iterate 4[sizeof(long)] * 8[number of loops] = 0x20 

		   //lea	$20(a3),a3	; next tile

	      }  //dbf	d0,@loadtile	; repeat for number of tiles

	   }  //dbf	d1,@readentry	; repeat for number of entries
	}  
    }
    //@nochange:
    //		rts	
}

/*   
SonicPlayer:
.
  use obRoutine as a value of the index in the list of sonic subroutines to jump to: Sonic_Main, Sonic_Control, Sonic_Hurt, Sonic_Death, Sonic_ResetLevel
  
  SonicMain:
  add 2 to obRoutine 
  obHeight=$13, obWidth = $9, obMap = location of sonics mappings, obGfx=$780, obPriority=2, obActWid=$18, obRender=4, v_sonspeedmax=$600 (sonics top speed), v_sonspeedacc=$C (sonic's acceleration), v_sonspeeddec=$80 (sonic's deacelleration)
  continue with SonicControl (why we add 2 to obRoutine)
  
  SonicControl:
  if debug mode and b is pressed then v_debuguse=1 and clear (f_lockctrl) and end execution of sonic object
  if controls are not locked (f_lockctrl) then enable joypad control
  
  also test f_lockmulti a secondary control lock if not locked then bit 6 of obStatus is used in addition with Sonic_Modes to jump to the proper sonic mode
  if secondary control lock is locked then
  
     Display Sonic (Sonic_Display)
	 Record Sonic's Position (Sonic_RecordPosition)
	 Handle Water for Sonic (Sonic_Water)
	 Sonic angle=obAngle
	 additional value moved here (object subtype?)
	 if sonic is not in tunnel mode (f_wtunnelmode) and sonic is not changing frames (obAnim) then obAnim=obNextAni
	 Animate Sonic (Sonic_Animate)
	 if secondary lock is negative then sonic is only looping (Sonic_Loops) and graphics are to be loaded (Sonic_LoadGfx) then end execution of sonic object
	 else sonic is reacting to an item (ReactToItem)
   
    [SonicModes]
	Sonic_MdNormal (Normal Mode)
	    Handle Jumping (Sonic_Jump)
	    Handle Slope Resistance (Sonic_SlopeResist)
		Handle Movement (Sonic_Move)
		Handle Rolling (Sonic_Roll)
		Handle Restriction of Sonic position to level bounds (Sonic_LevelBound)
		SpeedToPos (Update Camera for sonics potential repositioning if out of bounds)
	    Calculate Angle for Sonic's position (Sonic_AnglePos)
		Handle Slope Repelling (Sonic_SlopeRepel)
		
	Sonic_MdJump (Sonic currently Jumping)
	    Handle Sonic's Jump Height/duration    (Sonic_JumpHeight)
		Handle changing Sonic's Direction as jumping (Sonic_JumpDirection)
		Handle Restriction of Sonic position to level bounds (Sonic_LevelBound)
		Let Sonic Fall                (Obj_Fall)
		if bit 6 of object status 0 (sonic doing nothing) then obVelY=obVelY-28 
		Return Sonic's Jump Angle to 0 as he jumps (Sonic_JumpAngle)
		Handle Interacting with the floor after jumping/falling (Sonic_Floor)
		
	Sonic_MdRoll (Sonic currently Rolling)
        Handle Jumping (Sonic_Jump)
        Handle Repelling from Rolling (Sonic_RollRepel)
        Handle Speeding from Rolling (Sonic_RollSpeed)
		Handle Restriction of Sonic position to level bounds (Sonic_LevelBound)
		SpeedToPos (Update Camera for sonics potential repositioning if out of bounds)
        Calculate Angle for Sonic's position (Sonic_AnglePos)
		Handle Slope Repelling (Sonic_SlopeRepel)
		
	Sonic_MdJump2 is an exact copy of Sonic_MdJump?
	
	
==== sonic object main subroutines ====
   Sonic_Jump:
   
   if A, B, or C not pressed then dont jump, end
   v_anglebuffer=obAngle+$80, FFFFF76A=obAngle+$80
   if ((obAngle+$100) & $C0) = $40 then subroutine for sonic run on walls
      use angle buffer 
	  FindWall (d2=obY-obWidth, d3=(obX-obHeight) | $F, a3=-$10, d6=$800, d5=$E), a4=angleBuffer
	  move calculated jump height restrictions from FindWall to stack
	  FindWall (d2=obY-obWidth, d3=(obX+obHeight) | $F, a3=$10, d6=$800, d5=$E), a4=$FFFFF76A
	  grab value from stack into d0
	  this means d1 also has newly calculated restriction
	  d2 = 40
	  compare first restriction (d0) with second restriction (d1)
	  use value at $FFFFF67A
      if less than or equal then skip to *
	    else use value at angleBuffer
	    swap the 2 restrictions (d0) and (d1)
	  *test bit 0 of (obX+obHeight) if 0 then exit if
	  d3=d2 (40)	 
   else if ((obAngle+$100) & $C0) = $80 then subroutine for sonic dont run on walls
      
   else if ((obAngle+$100) & $C0) = $C0 then subroutine for 
      
   compare 6 with second restriction (d1) if any less then 6 then skip rest of sub
      d2=680 ( if bit 6 of object status (obStatus) = 0 then d2=380)
      CalcAngle called with (obAngle-$40)
	   calculated cosine value = d2 * calculated cosine value
	   calculated cosine value = (calculated cosine value / 256)
	   obVelX=obVelX+calculated cosine value
	  calculated sine value = d2 * calculated sine value
	   calculated sine value = (calculated sine value / 256)
	   obVelY=obVelY+calculated sine value
	  
	  set bit 1 of obStatus & clear bit 5 of obStatus
	  add 4 to stack pointer
	  object variable ($3C) = 1 and clear object variable ($38)
	  
	  play jump sound effect
	  
	  if bit 2 of objStatus=1 then 
	     set bit 4 of objStatus
	     obHeight=13, obWidth=9
	  else
	     obHeight=$E, obWidth=7
		 obAnim=id_Roll
		 set bit 2 of objStatus
		 add 5 to obY
    ----
	
	Sonic_SlopeResist:
	
	    get obAngle + $60
		if this is = $C0 then end subroutine
		otherwise call calcSine on obAngle
		multiply $20 (32) with calculated sine value 
		divide this new value by 256
		test obInertia if 0 then end subroutine
		if negative then add new value to obInertia
		if this value is not usable then end subroutine
		also add new value to obInertia
	
	----
	
	Sonic_Move:
	
	    use v_sonspeedmax, v_sonspeedacc, v_sonspeeddec
		test f_jumponly if this is not 0 then
		
		   loc_12FEE:
		   call calcSine on obAngle
		   add $40 to sine value if negative then exit subroutine sonic does not move
		   replace cosine value with $40
		   test obInertia if 0 then exit subroutine sonic does not move
		   if obInertia is negative then negate cosine value
		   add cosine value (which means this is no longer a cosine value) to obAngle and put this on the stack
		   call SonicWalkSpeed
		   reload this value off of stack as it is modified in SonicWalkSpeed, this value is (d0)
		   if the cosine value was positive then exit subroutine
		
		   multiply cosine value by 256 
		
		   add $20 to the (d0) value, and AND the (d0) value with $C0
        
		   if new value is 0 then add new scaled cosine value to obVelY and exit subroutine
           else if it is 40 then 
		   -subtract new scaled cosine value from obVelX
           -set bit 5 of obStatus
           -obInertia = 0		
		   -exit subroutine
		   else if it is 80 then subtract new scaled cosine value from obVelY and exit subroutine 
		   else
		   -add new scaled cosine value to obVelX
		   -set bit 5 of obStatus
		   -obInertia = 0
		   -exit subroutine
		   
	    else subroutine is not exited and continued..
	    test object variable ($3A) if this is not 0 then Sonic_ResetScr
	
	    if control left is being pressed then Sonic_MoveLeft
	    if control right is being pressed then Sonic_MoveRight
	    get obAngle, add $20, and AND the value with $C0  (apparently this is the case when sonic is on a slope if the value is nonzero)
	    if value is nonzero then Sonic_ResetScr
	    if obInertia is nonzero (sonic is moving) then Sonic_ResetScr
	    clear bit 5 of obStatus
	    obAnim=id_Wait
	    test bit 3 of obStatus if 0 then Sonic_Balance
	    get value of object variable $3D and multiply by 64
	    add value to offset v_objspace, this gives the offset of a new object
	    test obStatus of object if negative then Sonic_LookUp

	    add sonic obX to obActWid to get new value
	    subtract object obX from this new value
	    if this is less than 4 then loc_12F6A
		   set bit 0 of obStatus
		   obAnim = id_Balance
		   execute Sonic_Reset_Scr
	    else if this is greater than (obActWid*2)-4 then loc_12F5A
		   clear bit 0 of obStatus
		   obAnim = id_Balance
		   execute Sonic_Reset_Scr
	    else Sonic_LookUp
		   if up not pressed then Sonic_Duck
		      if down not pressed then 
			     execute Sonic_Reset_Scr (ends subroutine this is a jump)
              else
                 obAnim = id_Duck (use ducking animation)
                 if v_lookshift = 8 then execute Sonic_Reset_Scr without checking and resetting v_lookshift
                 else subtract 2 from v_lookshift then execute Sonic_Reset_Scr without checking and resetting v_lookshift
	       else up is pressed so
		      obAnim = id_LookUp (use looking up animation)
			  if v_lookshift = $C8 then execute Sonic_Reset_Scr without checking and resetting v_lookshift
              else add 2 to v_lookshift then execute Sonic_Reset_Scr without checking and resetting v_lookshift
	----
	    
    Sonic_Balance:
        ObjFloorDist called
		if value returned (d1) less than $C then Sonic_LookUp
		if Object Variable ($36) != 3 then
		   if Object Variable ($37) != 3 then Sonic_LookUp and set bit 0 of obStatus jump to **
		else clear bit 0 of obStatus
		**obAnim = id_Balance
		Sonic_Reset_Scr called
	
	----
	
    Sonic_Reset_Scr:
	    if v_lookshift = 60 (screen is in its default position) then 
		   if carry bit not set then add 4 to v_lookshift
		   otherwise add 4 to -and- subtract 2 from v_lookshift
		if control left or right is pressed then to 12FEE
		if obInertia=0 then to 12FEE
		if obInertia is negative then to 12FE2
		subtract d5(sonSpeedAcceleration) from temp obInertia value
		if carry bit not clear then clear this value
		12FE2: obInertia=calculated temp value
		12FEE: call CalcSine with obAngle
		obVelX=(obInertia*calculated cosine value)/256
		obVelY=(obInertia*calculated sine value)/256
		if (obAngle+40) is neg then exit subroutine
		d1=40
		if obInertia=0 then exit subroutine
		if obInertia is positive then negate d1 (40)
		
		add obAngle to d1 and move result value onto stack as it is modified by next call
		SonicWalkSpeed called
		get value back from stack
		
		if d1 is positive (40) then exit subroutine
		d1=(d1*256)    (calc new scaled d1 value)
		
		add $20 to old (obAngle+d1) value grabbed from stack and AND with $C0
		if this value is zero (sonic is not on a slope)
		   -obVelY = obVelY + new scaled d1 value
		   -exit subroutine
		if this value is 40 then
		   -obVelX = obVelX - new scaled d1 value
		   -set bit 5 of obStatus
		   -obInertia = 0
		   -exit subroutine
		if this value is 80 then
		   -obVelY = obVelY - new scaled d1 value
		   -exit subroutine
		else
		   -obVelX = obVelX + new scaled d1 value
		   -set bit 5 of obStatus
		   -obInertia = 0
		   -exit subroutine
	
	----
	
	Sonic_MoveLeft:
	    if obInertia = 0 then
		   set bit 0 of obStatus
		   
		   if this already set then
		      clear bit 5 of obStatus
			  obNextAni=1
			
			temp accel value = obInertia - v_sonspeedacc
			temp max speed value = -(v_sonspeedmax)
			if temp max speed value <= temp accel value then
			   temp accel value = temp max speed value
            
            obInertia = temp accel value
			obAnim = id_Walk
		else
	        temp accel value = obInertia - v_sonspeeddec
			if carry bit not clear then temp accel value = -$80
			obInertia = temp accel value
			
			temp scaled angle value = (obAngle + $20) & $C0
		    if this is nonzero then exit subroutine
			if this is >= $400 then exit subroutine
			else..
			
			obAnim=id_Stop
			clear bit 0 of obStatus
			play stopping sound effect
	
	----
			
	Sonic_MoveRight:     (moves sonic right by: setting status flag for moving right and if already moving right then clearing (idle?) status flag and setting next
                          animation to 1(walk right?), accumulating sonics inertia with sonics acceleration value (restricted to sonics maximum speed), and changing sonic's animation to walk--ALL given that sonic has positive inertia 
						  IF sonic has negative inertia then accumulate this with sonics deceleration value and if sonic is on an angle of 0 then change animation to stop, clear status flag for moving right, and playing the stopping sound effect) 
	    if obInertia >= 0 then
		   set bit 0 of obStatus
		   
		   if this already set then
		      clear bit 5 of obStatus
			  obNextAni=1
			
			temp accel value = obInertia + v_sonspeedacc
			if v_sonspeedmax >= temp accel value then
			   temp accel value = v_sonspeedmax
            
            obInertia = temp accel value
			obAnim = id_Walk
		else
	        temp accel value = obInertia + v_sonspeeddec
			if carry bit not clear then temp accel value = $80
			obInertia = temp accel value
			
			temp scaled angle value = (obAngle + $20) & $C0
		    if this is nonzero then exit subroutine
			if this is >= -$400 then exit subroutine
			else..
			
			obAnim=id_Stop
			clear bit 0 of obStatus
			play stopping sound effect
	
	----
	
	Sonic_WalkSpeed: (in sonic.asm)      (adjusts sonic's position appropriately due to X and Y velocity values and adjusts position to Floor or Wall depending on angle)	

	   obX+(obVelX*256) calculated and swapped
       obY+(obVelY*256) calculated and swapped
	   
	   v_anglebuffer = sine value
	   FFFFF67A = sine value
	   add $20 to sine value 
	   
	   if this is positive then 
	      use original sine value 
		  if this is positive then add $1F 
		  else add $20
	   otherwise
    	  use original sine value 
		  if this is negative or zero then add $1F 
		  else add $20
	   
	   AND this value with $C0
	   if this is 0 then... 14df0
	   
	      add $A to new obY value
		  FindFloor(a3=$10, d6=0, d5=$E, a4=v_anglebuffer)
		  new obY value=0
		  
		  test bit 0 of v_anglebuffer if this is nonzero then
		     new obX value = 0
		  exit subroutine
	   
	   else if this is 80 then... 14f7c(final portion of Sonic_DontRunOnWalls)
	   
	      new obY value = new obY value - $A
		  new obY value = new obY value OR $F
		  FindFloor(a3=-$10, d6=$1000, d5=$E, a4=v_anglebuffer)
	      new obY value = -$80
		  
		  test bit 0 of v_anglebuffer if this is nonzero then
		     new obX value = 0
		  exit subroutine
		  
	   else 

          AND sine value with $38
	 	  if this is 0 then add 8 to temp obY value 
		  also check at *
	   
	   *if this is 40 then... 1504a(final portion of Sonic_HitWall, subroutine to stop sonic when he jumps at a wall-loading orig obX and obY values is skipped)
	      
		  new obX value = new obX value - $A
		  new obX value = new obX value OR $F
		  FindWall(a3=-$10, d6=$800, d5=$E, a4=v_anglebuffer)
		  new obY value = $40

		  test bit 0 of v_anglebuffer if this is nonzero then
		     new obX value = 0
		  exit subroutine
		  
	   else...  14ebc (some sub referenced by Sonic_Floor
	   
	      new obX value = new obX value + $A
		  FindWall(a3=$10, d6=0, d5=$E, a4=v_anglebuffer)
		  new obY value = -$40
		  
		  test bit 0 of v_anglebuffer if this is nonzero then
		     new obX value = 0
		  exit subroutine
	----
	
	Sonic_Roll:  (allows sonic to roll given that he isnt already jumping, he isnt moving too fast, left and right aren't pressed, and the appropriate button down is being pressed by setting flag 2 of sonic's Status(rolling), resetting Height and Width, changing appropriate animations, accounting for the offset of the roll animation by adding 5 to sonic's Y position, playing the rolling sound effect, and resetting sonic's inertia appropriately)
	
		test f_jumponly if this is not 0 then skip rest of subroutine (DO NOT ROLL)
		if obInertia is 0 or negative then change to make it positive
		if this is < $80 then (sonic not moving at $80 speed or faster) skip rest of subroutine (DO NOT ROLL)
		if left or right is being pressed then skip rest of subroutine (DO NOT ROLL)
		if down is being pressed then
		   test bit 2 of obStatus (if sonic is not already rolling) then
		      set bit 2 of obStatus
			  obHeight=$E
			  obWidth=7
			  obAnim=id_Roll
			  obY=obY+5
			  play rolling sound effect
			  test obInertia (if sonic moving) if nonzero then exit subroutine
			  else obInertia = $200
	----
	
	Sonic_LevelBound: (resets sonics variables for position velocity and inertia if trying to leave the left or right boundaries
						 also checks if sonic is below bottom of the screen, appropriately killing sonic if this is true; (case
						 different for SBZ1-3)
	
		new X value = (obVelX*256)+obX calculated and swapped
		if new X value > (v_limitleft2+$10) then check @sides: (has sonic touched the left boundary
			obX = v_limitleft2 + $10
			obX+2 = 0
			obVelX = 0
			obInertia = 0
			also check @bottom at *
		
		use new right limit value: (v_limitright2+$128)
		if f_lockscreen zero then add $40 to right limit value
	    if new X value < right limit value then check @sides (has sonic touched the right boundary)
			obX = v_limitleft2 + $10
			obX+2 = 0
			obVelX = 0
			obInertia = 0
			also check @bottom at *
		
		*if obY < (limit_btm + $E0) then @bottom
		    if v_zone != (id_SBZ<<8)+1 (zone not scrap brain) then KillSonic 
		    compare obX with $2000 if carry set then KillSonic (for scrap brain)
			else at this point we are at SBZ2 where we 
			clear v_lastlamp (clear lamppost counter)
			f_restart=1 (restart the level)
			v_zone = (id_LZ<<8)+3  (set level to SBZ3)
		exit subroutine
		
	
	Sonic_AnglePos:  (change sonic's angle and position as he walks along the floor)
	
		if bit 3 of obStatus = 1 then FFFFF768 = 0, FFFFF76A = 0, and exit subroutine
		FFFFF768 = 3, FFFFF76A = 3
		if obAngle+$20 is positive then
		   if obAngle is 0 or negative then add $20 to temp obAngle 
		   else add $1F to temp obAngle
		else 
		   if obAngle is 0 or negative then add $20 - 1 to temp obAngle
		   else add $20 to temp obAngle
		AND temp obAngle with $C0
		
		if this is $40 then Sonic_WalkVertL
		if this is $80 then Sonic_WalkCeiling
		if this is $C0 then Sonic_WalkVertR
		
		else
		FindFloor(d2=obX+obWidth, d3=obY+obHeight, a4=FFFFF76A, a3=$10, d6=0, d5=$D)
		move the found floor value onto stack (d1)
		FindFloor(d2=obX-obWidth, d3=obY+obHeight, a4=FFFFF76A, a3=$10, d6=0, d5=$D)
		grab old floor value from stack into (d0), with new floor value in (d1)
		
		Sonic_Angle called (subroutine for change sonic's angle as he walks along the floor)
		if d1 (returned value) = 0 then exit subroutine
		else if positive then
		   if d1 (returned value) <= $E then 
		      add d1 to obY
		   else
		      test object variable ($38) if nonzero then
			     add d1 to obY
		      else
			     set bit 1 of obStatus
				 clear bit 5 of obStatus
				 obNextAni = 1
		else if -$E < d1 (returned value) then exit subroutine
		else add d1 (returned value) to obY
	----

    Sonic_Angle:  (d0=floor 1 value, d1=floor 2 value)
       
       d2=(FFFFF76A)
	   if floor1 value > floor2 value then 
	      d2=(FFFFF768)
		  floor2 value = floor1 value
	   if bit 0 of d2 = 0 then 
	      obAngle=d2
	      exit subroutine
	   else
	      obAngle = (obAngle + $20) AND $C0
		
	----
	
	Sonic_WalkVertR:
	
	    FindWall(d2=obY-obWidth, d3=obX+obHeight, a4=FFFFF768, a3=$10, d6=0, d5=$D)
        move the found wall value onto stack (d1)
        FindWall(d2=obY+obWidth, d3=obX+obHeight, a4=FFFFF76A, a3=$10, d6=0, d5=$D)
		grab old wall value back off stack to (d0), new value in (d1)
		Sonic_Angle called (subroutine for change sonic's angle as he walks along the floor)
		if new wall value is 0 then exit subroutine
		if new wall value is positive then
			if $E > then new wall value then
			if object variable $(38) !=0 then
		if -$E < new wall value then exit subroutine
		add new wall value to obX
	

	----
	
	Sonic_WalkVertL:
	
	    ....
		
	----
	
	Sonic_WalkCeiling:
	
		....
		
	----
	
	Sonic_Animate:		(handles changing sonics animation frame/group depending on the constraints that change it)
	
	   if obAnim != obNextAnim (is animation not set to restart?)
	      obNextAnim=obAnim
		  obAniFrame=0
		  obTimeFrame=0
		  
	   get value at Ani_Sonic+(obAnim*2)
	   if negative then walkRunRoll
	   else
	      (obStatus & 1) | (obRender & $FC)
	      obTimeFrame = obTimeFrame - 1
	      if obTimeFrame > 0 then delay animation by skipping rest of animate subroutine (exit sub)
	      else obTimeFrame = value at Ani_Sonic+(obAnim*2)
	   
	   loadFrame:
	   (Ani_Sonic+(obAnim*2))+(obAniFrame+1)       (read current frame for current animation)
	   if this is < 0 then                         (animation is complete)
		   add 1 to temp current frame
		   if this is > 0 then
		      add 1 to temp current frame
			  if this is > 0 then
			      add 1 to temp current frame
				  if this is > 0 then exit sub
				  else obAnim = value at (2+address of current frame)
			  else
			      grab value at 2+address of current frame 
				  obAniFrame = obAniFrame - this value
				  subtract new obAniFrame from old temp obAniFrame (distance between both frames)
				  use value at (1+(this distance)+Ani_Sonic)
				  go to @next
			else
			      obAniFrame = 0                           (restart the animation)
				  use value d0 = 1 + (Animation offset)    (old Ani_Sonic+(obAnim*2))
				  go to @next
		else @next:
		   obFrame = d0
		   obAniFrame = obAniFrame + 1
		
		END OF SUBROUTINE
		
		WalkRunRoll:
		
		    obTimeFrame = obTimeFrame - 1
			if obTimeFrame > 0 then exit subroutine
			current anim (d0) = current anim + 1
			if nonzero then animation not walking/running: @rolljump
			d0 = obAngle                          (use objects angle)
			if (obStatus & 1) = 0 then NOT d0     (if sonic is not mirrored horizontally then reverse calculated angle)
            d0 = d0 + 10                          (add 10 to calculated angle)
			if negative (angle is $80-$FF) then d1 = 3 else d1 = 0  (account for invert)
			obRender = obRender & FC
			obRender = obRender | ( (obStatus & 1) | (obRender) )
			if bit 5 of obStatus is nonzero then @push
			else
			d0 = (d0 / $10)       (divide angle by $10)
			d0 = d0 & 6
			if temp obInertia is negative then negate temp obInertia
			a1=SonAni_Run
			if this temp obInertia value is not 600 then a1=SonAni_Walk and d0 = d0 + (d0/2)  (add to temp object angle)
			d0=(d0 * 2)                                                                       (scale temp object angle)
			negate temp obInertia value and add $800
			if this is negative (above max speed) then replace with 0
			temp obInertia = temp obInertia / $256
			obTimeFrame = temp obInertia                                                      (modify frame duration)
			repeat from loadFrame to end of subroutine
			obFrame = obFrame + d0                                                            (modify frame number)
			
			END OF SUBROUTINE
			
			@rolljump:
			
				current anim (d0) = current anim + 1
				if this is nonzero then @push                                                (if animation is not rolling/jumping)
                if temp obInertia is negative then negate temp obInertia
				a1=Son_AniRoll2
				if temp obInertia != 600 then a1=Son_AniRoll
				negate temp obInertia and add $400
				if this is negative then replace with 0
				temp obInertia = temp obInertia / 256
				obTimeFrame = temp obInertia												(modify frame duration)
				obRender = obRender & $FC
				obRender = obRender | ( (obStatus & 1) | (obRender) )
				goto loadFrame
				
			@push:
			
			    if temp obInertia is positive then negate temp obInertia
				add $800 to temp obInertia
				if this is negative then replace with 0
				temp obInertia = temp obInertia / 64
				obTimeFrame = temp obInertia
				a1=Son_AniPush
				obRender = obRender & $FC
				obRender = obRender | ( (obStatus & 1) | (obRender) )
				goto loadFrame
				*/
				
				
			
/*void objPosLoad()
{
   if (v_opl_routine == 0)		//this is main object loading routine, accomplished by jumping to the proper code via a relative index in the assembly 
   {
      v_opl_routine += 2;
	  v_opl_data = ObjPos_*/
	  

	
